This file is used to prepare the figures for the paper.

library(dplyr)
library(patchwork)
library(ggplot2)
library(ComplexHeatmap)
library(org.Mm.eg.db)

.libPaths()
## [1] "/usr/local/lib/R/library"

Preparation

Here are the folders where analyzes are stored :

data_dir = "./.."
list.files(data_dir)
## [1] "0_intro"      "1_metadata"   "2_individual" "3_combined"   "4_zoom"      
## [6] "5_figures"    "LICENSE"      "index.html"   "index_layout"

We load the dataset containing all cells :

sobj = readRDS(paste0(data_dir, "/3_combined/hs_hd_sobj.rds"))
sobj
## An object of class Seurat 
## 20003 features across 12111 samples within 1 assay 
## Active assay: RNA (20003 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_38_tsne, RNA_pca_38_umap, harmony, harmony_38_umap, harmony_38_tsne

These are all the samples analyzed :

sample_info = readRDS(paste0(data_dir, "/1_metadata/hs_hd_sample_info.rds"))

# Nb cells by dataset
to_plot = table(sobj$sample_identifier) %>%
  as.data.frame.table(., stringsAsFactors = FALSE) %>%
  `colnames<-`(c("sample_identifier", "nb_cells")) %>%
  dplyr::left_join(x = ., y = sample_info, by = "sample_identifier") 

# patchwork
plot_list = aquarius::fig_plot_gb(to_plot, title = "Available datasets")
patchwork::wrap_plots(plot_list) +
  patchwork::plot_layout(design = "A\nB", heights = c(0.1,5)) &
  ggplot2::theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 15))

These are the custom colors for cell populations :

color_markers = readRDS(paste0(data_dir, "/1_metadata/hs_hd_color_markers.rds"))
color_markers = color_markers[names(color_markers) != "melanocytes"]
ors_color = color_markers["ORS"]
color_markers["ORS"] = color_markers["IFE"] 
color_markers["IFE"] = ors_color
color_markers["B cells"] = "chocolate3"
rm(ors_color)

data.frame(cell_type = names(color_markers),
           color = unlist(color_markers)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers), breaks = names(color_markers)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank(),
                 axis.text.x = element_text(hjust = 1, angle = 20))

We define custom colors for sample type :

sample_type_colors = setNames(nm = levels(sample_info$sample_type),
                              c("#C55F40", "#2C78E6"))

data.frame(cell_type = names(sample_type_colors),
           color = unlist(sample_type_colors)) %>%
  ggplot2::ggplot(., aes(x = cell_type, y = 0, fill = cell_type)) +
  ggplot2::geom_point(pch = 21, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(sample_type_colors), breaks = names(sample_type_colors)) +
  ggplot2::theme_classic() +
  ggplot2::theme(legend.position = "none",
                 axis.line = element_blank(),
                 axis.title = element_blank(),
                 axis.ticks = element_blank(),
                 axis.text.y = element_blank())

We set a background color :

bg_color = "gray94"

This is the correspondence between cell types and cell families, and custom colors to color cells by cell family :

custom_order_cell_type = data.frame(
  cell_type = names(color_markers),
  cell_family = c(rep("immune cells", 5),
                  rep("matrix", 5),
                  rep("non matrix", 5)),
  stringsAsFactors = FALSE)
custom_order_cell_type$cell_type = factor(custom_order_cell_type$cell_type,
                                          levels = custom_order_cell_type$cell_type)
rownames(custom_order_cell_type) = custom_order_cell_type$cell_type

family_color = c("immune cells" = "slateblue1",
                 "matrix" = "mediumseagreen",
                 "non matrix" = "firebrick3")

We load markers to display on a dotplot to assess cell type annotation :

dotplot_markers = readRDS(paste0(data_dir, "/1_metadata/hs_hd_dotplot_markers.rds"))
dotplot_markers = dotplot_markers[names(dotplot_markers) != "melanocytes"]
lengths(dotplot_markers)
##      CD4 T cells      CD8 T cells Langerhans cells      macrophages 
##                2                2                2                2 
##          B cells          cuticle           cortex          medulla 
##                2                2                2                2 
##              IRS    proliferative              IBL              ORS 
##                2                2                2                2 
##              IFE             HFSC        sebocytes 
##                2                2                2

Custom functions to display gene expression on the heatmap :

color_fun = function(one_gene) {
  gene_range = range(ht_annot[, one_gene])
  gene_palette = circlize::colorRamp2(colors = c("#FFFFFF", aquarius::color_gene[-1]),
                                      breaks = seq(from = gene_range[1], to = gene_range[2],
                                                   length.out = length(aquarius::color_gene)))
  return(gene_palette)
}

All samples

Settings

This is the projection name to visualize cells :

name2D = "harmony_38_tsne"
name2D_atlas = name2D

Preparation

We make a low resolutive clustering for the heatmap :

sobj = Seurat::FindClusters(sobj, resolution = 0.4)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 12111
## Number of edges: 475472
## 
## Running Louvain algorithm...
## Maximum modularity in 10 random starts: 0.9421
## Number of communities: 17
## Elapsed time: 1 seconds
length(levels(sobj$seurat_clusters))
## [1] 17

We define cluster type and cluster family :

cluster_type = table(sobj$cell_type, sobj$seurat_clusters) %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cluster_type = setNames(nm = names(cluster_type),
                        levels(sobj$cell_type)[cluster_type])

sobj$cluster_type = cluster_type[sobj$seurat_clusters]
sobj$cluster_type = factor(sobj$cluster_type,
                           levels = levels(sobj$cell_type))
sobj$cluster_family = custom_order_cell_type[sobj$cluster_type, "cell_family"]
sobj$cluster_family = factor(sobj$cluster_family,
                             levels = names(family_color))

Figures

Project name :

# Random order
set.seed(1234)
rnd_order = sample(colnames(sobj), replace = FALSE, size = ncol(sobj))

# Extract coordinates
cells_coord = sobj@reductions[[name2D]]@cell.embeddings %>%
  as.data.frame() %>%
  `colnames<-`(c("Dim1", "Dim2"))
cells_coord$project_name = sobj$project_name
cells_coord = cells_coord[(rnd_order), ]

# Plot
ggplot2::ggplot(cells_coord, aes(x = Dim1, y = Dim2, col = project_name)) +
  ggplot2::geom_point(size = 0.5) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  ggplot2::theme_void() +
  ggplot2::theme(aspect.ratio = 1,
                 legend.position = "none")

Cluster :

Seurat::DimPlot(sobj, reduction = name2D, pt.size = 0.4,
                group.by = "seurat_clusters", label = TRUE) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cell type annotation :

Seurat::DimPlot(sobj, reduction = name2D, pt.size = 0.5,
                group.by = "cell_type", cols = color_markers) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cluster family annotation :

Seurat::DimPlot(sobj, reduction = name2D, pt.size = 0.5,
                group.by = "cluster_family", cols = family_color) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cell type annotation split by condition :

plot_list = aquarius::plot_split_dimred(sobj, reduction = name2D,
                                        group_by = "cell_type",
                                        group_color = color_markers,
                                        split_by = "sample_type",
                                        split_color = sample_type_colors,
                                        bg_color = bg_color)

patchwork::wrap_plots(plot_list) &
  Seurat::NoLegend()

Gene expression to assess annotation :

genes = c("PTPRC", "MSX2", "KRT14")
names(genes) = c("immune cells", "matrix cells", "non-matrix cells")

plot_list = lapply(c(1:length(genes)), FUN = function(gene_id) {
  gene = genes[[gene_id]]
  pop = names(genes)[gene_id]
  
  sobj$my_gene = Seurat::FetchData(sobj, gene)[, 1] %>%
    aquarius::run_rescale(., new_min = 0, new_max = 10)
  
  Seurat::FeaturePlot(sobj, features = "my_gene", reduction = name2D) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene,
                                   breaks = seq(0, 10, by = 2.5),
                                   labels = c("min", rep("", 3), "max")) +
    ggplot2::labs(title = gene) + 
    # subtitle = pop) +
    ggplot2::theme(aspect.ratio = 1,
                   plot.title = element_text(hjust = 0.5, size = 17),
                   plot.subtitle = element_text(hjust = 0.5, size = 15),
                   legend.text = element_text(size = 15),
                   legend.position = "none") +
    Seurat::NoAxes()
})

plot_list
## [[1]]

## 
## [[2]]

## 
## [[3]]

Barplot by cluster family :

quantif = table(sobj$sample_identifier) %>%
  as.data.frame.table() %>%
  `colnames<-`(c("Sample", "nb_cells"))

aquarius::plot_barplot(df = table(sobj$sample_identifier,
                                  sobj$cluster_family) %>%
                         as.data.frame.table() %>%
                         `colnames<-`(c("Sample", "Cell Type", "Number")),
                       x = "Sample", y = "Number", fill = "Cell Type",
                       position = position_fill()) +
  ggplot2::geom_label(data = quantif, inherit.aes = FALSE,
                      aes(x = .data$Sample, y = 1.05, label = .data$nb_cells),
                      label.size = 0, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(family_color),
                             breaks = names(family_color),
                             name = "Cell Family") +
  ggplot2::scale_y_continuous(breaks = seq(0, 1, by = 0.25),
                              labels = paste0(seq(0, 100, by = 25), sep = " %"),
                              expand = ggplot2::expansion(add = c(0, 0.05))) +
  ggplot2::theme(axis.title.y = element_blank(),
                 axis.line.x = element_line(colour = "lightgray"),
                 text = element_text(size = 15),
                 legend.position = "none")

Heatmap of cluster proportion by sample :

group_by = "seurat_clusters"

cluster_by_sample = table(sobj$sample_identifier,
                          sobj@meta.data[, group_by]) %>%
  prop.table(margin = 1) %>%
  as.matrix()

## Representative markers
cluster_markers = c("PTPRC", "CD3E", "AIF1", "MSX2", "DIO2", "GPX2", "KRT16")
ht_annot = Seurat::GetAssayData(sobj, assay = "RNA", slot = "data")[cluster_markers, ] %>%
  Matrix::t() %>% as.data.frame()
ht_annot$clusters = sobj@meta.data[, group_by]
ht_annot = ht_annot %>%
  dplyr::group_by(clusters) %>%
  dplyr::summarise_all(funs('mean' = mean)) %>%
  as.data.frame() %>%
  dplyr::select(-clusters) %>%
  `colnames<-`(c(cluster_markers))

## Bottom annotation : average gene expression
ha_bottom = ComplexHeatmap::HeatmapAnnotation(df = ht_annot,
                                              which = "column",
                                              show_legend = FALSE,
                                              col = setNames(nm = cluster_markers,
                                                             lapply(cluster_markers, FUN = color_fun)),
                                              annotation_name_side = "right")

## Right annotation : number of cells by dataset
ht_annot = table(sobj$sample_identifier) %>%
  as.data.frame.table() %>%
  `colnames<-`(c("sample_identifier", "nb_cells")) %>%
  `rownames<-`(.$sample_identifier) %>%
  dplyr::select(-sample_identifier)

ha_right = ComplexHeatmap::HeatmapAnnotation(
  df = ht_annot,
  which = "row",
  show_legend = TRUE,
  annotation_name_side = "top",
  col = list(nb_cells  = circlize::colorRamp2(colors = RColorBrewer::brewer.pal(name = "Greys", n = 9),
                                              breaks = seq(from = range(ht_annot$nb_cells)[1],
                                                           to = range(ht_annot$nb_cells)[2],
                                                           length.out = 9))))

## Left annotation : gender
ha_left = ComplexHeatmap::HeatmapAnnotation(
  gender = sample_info$gender,
  which = "row",
  show_legend = TRUE,
  annotation_name_side = "bottom",
  col = list(gender = setNames(nm = c("F", "M"),
                               c("lightcyan3", "navyblue"))))

## Top annotation : main cell type in this cluster
ht_annot = table(sobj$sample_identifier,
                 sobj@meta.data[, group_by]) %>%
  prop.table(margin = 1) %>%
  as.matrix()

ht_annot = table(sobj$cell_type,
                 sobj@meta.data[, group_by]) %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
ht_annot = data.frame(row.names = names(ht_annot),
                      cell_type = names(color_markers)[ht_annot],
                      stringsAsFactors = FALSE)
ht_annot = dplyr::left_join(ht_annot, custom_order_cell_type, by = "cell_type") %>%
  # Simplification for matrix
  dplyr::mutate(cell_type = ifelse(cell_type %in% c("medulla", "cortex", "cuticle"), yes = "hair shaft", no = cell_type)) %>%
  # Simplification for T cells
  dplyr::mutate(cell_type = ifelse(cell_type %in% c("CD4 T cells", "CD8 T cells"), yes = "T cells", no = cell_type)) %>%
  # Simplification for APC
  dplyr::mutate(cell_type = ifelse(cell_type %in% c("Langerhans cells", "macrophages"), yes = "APC", no = cell_type)) %>%
  # Add color
  dplyr::mutate(color = as.character(color_markers[cell_type])) %>%
  dplyr::mutate(color = ifelse(cell_type == "hair shaft", yes = "#FFB6C1", no = color)) %>%
  dplyr::mutate(color = ifelse(cell_type == "T cells", yes = "#8A6EE6", no = color)) %>%
  dplyr::mutate(color = ifelse(cell_type == "APC", yes = "#9CAA4B", no = color))

ha_top = ComplexHeatmap::HeatmapAnnotation(
  cell_type = ht_annot$cell_type,
  # cell_family = ht_annot$cell_family,
  which = "column",
  show_legend = TRUE,
  annotation_name_side = "left",
  col = list(cell_type = setNames(nm = ht_annot$cell_type,
                                  ht_annot$color)
             #, cell_family = family_color
  ))

## Assemble heatmap
ht = ComplexHeatmap::Heatmap(cluster_by_sample,
                             heatmap_legend_param = list(title = "Proportion",
                                                         col = c("#2166AC", "#F7F7F7", "#B2182B")),
                             # bottom_annotation = ha_bottom,
                             right_annotation = ha_right,
                             left_annotation = ha_left,
                             top_annotation = ha_top,
                             cluster_rows = TRUE,
                             cluster_columns = TRUE,
                             row_title = "Sample",
                             row_names_gp = grid::gpar(names = sample_info$sample_identifier,
                                                       col = sample_info$color,
                                                       fontface = "bold"),
                             column_title = "Cluster",
                             column_names_centered = TRUE,
                             row_names_side = "left",
                             column_names_side = "top",
                             column_names_rot = 0)

## Draw !
ComplexHeatmap::draw(ht, merge_legends = TRUE)

Dotplot :

plot_list = aquarius::plot_dotplot(sobj,
                                   markers = c("PTPRC",
                                               "CD3E", "CD4",
                                               "CD3E", "CD8A",
                                               "CD207", "CPVL", 
                                               "TREM2", "MSR1",
                                               "CD79A", "CD79B",
                                               "KRT32", "KRT35",
                                               "KRT31", "PRR9",
                                               "BAMBI", "ADLH1A3",
                                               "KRT71", "KRT73",
                                               "TOP2A", "MCM5",
                                               "KRT16", "KRT6C",
                                               "KRT15", "GPX2",
                                               "SPINK5", "LY6D",
                                               "DIO2", "TCEAL2",
                                               "CLMP", "PPARG"),
                                   assay = "RNA", column_name = "cell_type", nb_hline = 0) +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(legend.position = "right",
                 legend.box = "vertical",
                 axis.title = element_blank(),
                 axis.ticks.x = element_blank(),
                 axis.text.x = element_blank(),
                 axis.line.x = element_blank(),
                 plot.margin = unit(rep(0, 4), "cm"))

p = ggplot2::ggplot(custom_order_cell_type, aes(x = cell_type, y = 0)) +
  ggplot2::geom_point(size = 0) +
  ggplot2::geom_segment(aes(x = 0.5, xend = 5.5, y = 0, yend = 0), size = 6, col = family_color["immune cells"]) +
  ggplot2::geom_segment(aes(x = 5.5, xend = 10.5, y = 0, yend = 0), size = 6, col = family_color["matrix"]) +
  ggplot2::geom_segment(aes(x = 10.5, xend = 15.5, y = 0, yend = 0), size = 6, col = family_color["non matrix"]) +
  ggplot2::scale_y_continuous(expand = c(0,0), limits = c(0,0)) +
  ggplot2::theme_classic() +
  ggplot2::theme(axis.text.y = element_blank(),
                 axis.ticks.y = element_blank(),
                 axis.title = element_blank(),
                 axis.line.y = element_blank(),
                 axis.text.x = element_text(angle = 45, hjust = 1, size = 10, color = "black"),
                 plot.margin = unit(rep(0, 4), "cm"))

plot_list = patchwork::wrap_plots(plot_list, p,
                                  ncol = 1, heights = c(25, 1))
plot_list

Immune cells

Settings

We load the immune cells dataset :

sobj_ic = readRDS(paste0(data_dir, "/4_zoom/1_zoom_immune/immune_cells_sobj.rds"))
sobj_ic
## An object of class Seurat 
## 15121 features across 2329 samples within 1 assay 
## Active assay: RNA (15121 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

This is the projection name to visualize cells :

name2D = "harmony_20_tsne"

To represent results from differential expression, we load the analyses results :

list_results = readRDS(paste0(data_dir, "/4_zoom/1_zoom_immune/immune_cells_list_results.rds"))

lapply(list_results, FUN = names)
## $`Langerhans cells`
## [1] "mark" "gsea"
## 
## $macrophages
## [1] "mark"       "enrichr_hs" "enrichr_hd" "gsea"      
## 
## $`CD4 T cells`
## [1] "mark"       "enrichr_hs" "enrichr_hd" "gsea"      
## 
## $`CD8 T cells`
## [1] "mark"       "enrichr_hs" "enrichr_hd" "gsea"

Preparation

We defined cluster type and cluster family :

cluster_type = table(sobj_ic$cell_type, sobj_ic$seurat_clusters) %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cluster_type = setNames(nm = names(cluster_type),
                        levels(sobj_ic$cell_type)[cluster_type])

sobj_ic$cluster_type = cluster_type[sobj_ic$seurat_clusters]
sobj_ic$cluster_type = factor(sobj_ic$cluster_type,
                              levels = levels(sobj_ic$cell_type))
sobj_ic$cluster_family = custom_order_cell_type[sobj_ic$cluster_type, "cell_family"]
sobj_ic$cluster_family = factor(sobj_ic$cluster_family,
                                levels = names(family_color))

Figures

Control cells on the full atlas :

sobj$is_immune = (colnames(sobj) %in% colnames(sobj_ic))

Seurat::DimPlot(sobj, reduction = name2D_atlas, pt.size = 0.000001,
                group.by = "is_immune", order = "TRUE") +
  ggplot2::scale_color_manual(values = c(family_color[["immune cells"]], bg_color),
                              breaks = c(TRUE, FALSE)) +
  ggplot2::labs(title = "Immune cells",
                subtitle = paste0(ncol(sobj_ic), " cells")) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5, face = "bold"),
                 plot.subtitle = element_text(hjust = 0.5)) +
  Seurat::NoAxes() + Seurat::NoLegend()

Violin plot of IL1B in macrophages :

subsobj = subset(sobj_ic, seurat_clusters == 2)
table(subsobj$sample_type)
## 
##  HS  HD 
## 378  31
il1b_hs = subsobj@assays$RNA@data["IL1B", subsobj$sample_type == "HS"]
il1b_hd = subsobj@assays$RNA@data["IL1B", subsobj$sample_type == "HD"]
il1b_hs_VS_il1b_hd = stats::t.test(il1b_hs, il1b_hd)
il1b_hs_VS_il1b_hd
## 
##  Welch Two Sample t-test
## 
## data:  il1b_hs and il1b_hd
## t = 2.3206, df = 35.801, p-value = 0.02612
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.05066074 0.75429252
## sample estimates:
## mean of x mean of y 
## 0.9256690 0.5231924
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "IL1B", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Split by sample :

Seurat::VlnPlot(subsobj, group.by = "sample_identifier",
                features = "IL1B", cols = sample_info$color) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Violin plot of IL1B in macrophages :

il6_hs = subsobj@assays$RNA@data["IL6", subsobj$sample_type == "HS"]
il6_hd = subsobj@assays$RNA@data["IL6", subsobj$sample_type == "HD"]
il6_hs_VS_il6_hd = stats::t.test(il6_hs, il6_hd)
il6_hs_VS_il6_hd
## 
##  Welch Two Sample t-test
## 
## data:  il6_hs and il6_hd
## t = 2.3591, df = 377, p-value = 0.01883
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.001453521 0.016004661
## sample estimates:
##   mean of x   mean of y 
## 0.008729091 0.000000000
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "IL6", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Violin plot of IL1B in macrophages :

subsobj = subset(sobj_ic, seurat_clusters == 2)
table(subsobj$sample_type)
## 
##  HS  HD 
## 378  31
tnf_hs = subsobj@assays$RNA@data["TNF", subsobj$sample_type == "HS"]
tnf_hd = subsobj@assays$RNA@data["TNF", subsobj$sample_type == "HD"]
tnf_hs_VS_tnf_hd = stats::t.test(tnf_hs, tnf_hd)
tnf_hs_VS_tnf_hd
## 
##  Welch Two Sample t-test
## 
## data:  tnf_hs and tnf_hd
## t = 3.8395, df = 45.546, p-value = 0.0003786
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.1140962 0.3657054
## sample estimates:
##  mean of x  mean of y 
## 0.31784960 0.07794879
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "TNF", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Split by sample :

Seurat::VlnPlot(subsobj, group.by = "sample_identifier",
                features = "TNF", cols = sample_info$color) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Violin plot of GZMA in CD4 T cells :

subsobj = subset(sobj_ic, seurat_clusters %in% c(0,10))
table(subsobj$sample_type)
## 
##  HS  HD 
## 569  90
gzma_hs = subsobj@assays$RNA@data["GZMA", subsobj$sample_type == "HS"]
gzma_hd = subsobj@assays$RNA@data["GZMA", subsobj$sample_type == "HD"]
gzma_hs_VS_gzma_hd = stats::t.test(gzma_hs, gzma_hd)
gzma_hs_VS_gzma_hd
## 
##  Welch Two Sample t-test
## 
## data:  gzma_hs and gzma_hd
## t = 14.755, df = 172.51, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  1.225578 1.604097
## sample estimates:
## mean of x mean of y 
## 1.8456108 0.4307735
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "GZMA", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

We represent some genes split by sample type :

plot_list = lapply(c("IL1B", "GZMA", "IFNG", "IL17A"), FUN = function(one_gene) {
  p = aquarius::plot_split_dimred(sobj_ic,
                                  reduction = name2D,
                                  split_by = "sample_type",
                                  color_by = one_gene,
                                  color_palette = c("gray70", "#FDBB84", "#EF6548", "#7F0000", "black"),
                                  main_pt_size = 0.6,
                                  bg_pt_size = 0.6,
                                  order = TRUE,
                                  bg_color = "gray95")
  p = patchwork::wrap_plots(p, nrow = 1) +
    patchwork::plot_layout(guides = "collect") +
    ggplot2::theme(legend.position = "right") &
    ggplot2::theme(plot.subtitle = element_blank())
  return(p)
})

patchwork::wrap_plots(plot_list, ncol = 2)

Barplot by cluster type :

quantif = table(sobj_ic$sample_identifier) %>%
  as.data.frame.table() %>%
  `colnames<-`(c("Sample", "nb_cells"))

aquarius::plot_barplot(df = table(sobj_ic$sample_identifier,
                                  sobj_ic$cluster_type) %>%
                         as.data.frame.table() %>%
                         `colnames<-`(c("Sample", "Cell Type", "Number")),
                       x = "Sample", y = "Number", fill = "Cell Type",
                       position = position_stack()) +
  ggplot2::geom_label(data = quantif, inherit.aes = FALSE,
                      aes(x = .data$Sample, y = 50 + .data$nb_cells, label = .data$nb_cells),
                      label.size = 0, size = 5) +
  ggplot2::scale_fill_manual(values = unlist(color_markers),
                             breaks = names(color_markers),
                             name = "Cell Type") +
  ggplot2::theme(axis.title.y = element_blank(),
                 axis.line.x = element_line(colour = "lightgray"),
                 text = element_text(size = 15),
                 legend.position = "none")

Dotplot of DE genes for macrophages :

subsobj = subset(sobj_ic, cluster_type == "macrophages")
features_oi = c("HLA-DQA2", "HLA-DPA1", "HLA-DRB5",
                "HLA-A", "HLA-C", "B2M",
                "C1QA", "C1QB", "C1QC")

Seurat::DotPlot(subsobj,
                assay = "RNA",
                features = features_oi,
                group.by = "sample_type",
                scale = FALSE) +
  ggplot2::coord_flip() +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(axis.title.x = element_blank(),
                 axis.title.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

Heatmap for macrophages :

# Matrix
mat_expr = Seurat::GetAssayData(subsobj)
mat_expr = mat_expr[features_oi, ]
mat_expr = Matrix::t(mat_expr)
mat_expr = dynutils::scale_quantile(mat_expr) # between 0 and 1
mat_expr = Matrix::t(mat_expr)
dim(mat_expr) # genes x cells
## [1]   9 463
## Colors
list_colors = list()

# Heatmap
list_colors[["expression"]] = rev(RColorBrewer::brewer.pal(name = "RdBu", n = 9))

# Sample annotation (top annotation)
list_colors[["sample_type"]] = sample_type_colors
list_colors[["sample_identifier"]] = setNames(nm = sample_info$sample_identifier,
                                              sample_info$color)
# Cells order
column_order = subsobj@meta.data %>%
  dplyr::arrange(sample_type, sample_identifier) %>%
  rownames()
column_order = match(column_order, rownames(subsobj@meta.data))

# Heatmap
ha_top = HeatmapAnnotation(sample_type = subsobj$sample_type,
                           sample_identifier = subsobj$sample_identifier,
                           col = list(sample_type = list_colors[["sample_type"]],
                                      sample_identifier = list_colors[["sample_identifier"]]))

# Heatmap
ht = Heatmap(as.matrix(mat_expr),
             heatmap_legend_param = list(title = "Expression", at = c(0, 1), 
                                         labels = c("low", "high")),
             col = list_colors[["expression"]],
             top_annotation = ha_top,
             show_column_names = FALSE,
             column_order = column_order,
             column_gap = unit(2, "mm"),
             cluster_rows = FALSE,
             row_title = NULL,
             row_names_gp = grid::gpar(fontsize = 14, fontface = "plain"),
             use_raster = FALSE,
             show_heatmap_legend = TRUE,
             border = TRUE)

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom",
                     annotation_legend_side = "bottom")

Dotplot of DE genes for CD4 T cells :

subsobj = subset(sobj_ic, cluster_type == "CD4 T cells")
# features_oi = c(
#   # HALLMARK_TNFA_SIGNALING_VIA_NFKB
#   "RIPK2", "KLF9", "PER1", "FOS", "BTG1", "PTGER4", "BIRC3", "AREG", "KLF6", "ZFP36", "NFKBIA",
#   # REACTOME_RHO_GTPASE_EFFECTORS
#   "CYBA", "ARPC3", "CFL1", "RPS27", "CALM1", "ACTB",
#   # GOBP_GRANZYME_MEDIATED_PROGRAMMED_CELL_DEATH_SIGNALING_PATHWAY
#   "BNIP3", "GZMA", "GZMB", "LAMP1", "NKG7", "SRGN", "UBE4B",
#   # GOBP_POSITIVE_REGULATION_OF_MEMORY_T_CELL_DIFFERENTIATION
#   "CD46", "HLA-DRA", "HLA-DRB1", "IL12RB1", "IL23A", "IL23R", "TNFSF4",
#   "KLRB1")
features_oi = c("GZMA", "KLRB1", "BTG1", "ZFP36", "NFKBIA", "TXNIP", "CXCR4")

Seurat::DotPlot(subsobj,
                assay = "RNA",
                features = features_oi,
                group.by = "sample_type",
                scale = FALSE) +
  ggplot2::coord_flip() +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(axis.title.x = element_blank(),
                 axis.title.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

Heatmap for CD4 T cells :

# Matrix
mat_expr = Seurat::GetAssayData(subsobj)
mat_expr = mat_expr[features_oi, ]
mat_expr = Matrix::t(mat_expr)
mat_expr = dynutils::scale_quantile(mat_expr) # between 0 and 1
mat_expr = Matrix::t(mat_expr)
dim(mat_expr) # genes x cells
## [1]   7 848
## Colors
list_colors = list()

# Heatmap
list_colors[["expression"]] = rev(RColorBrewer::brewer.pal(name = "RdBu", n = 9))

# Sample annotation (top annotation)
list_colors[["sample_type"]] = sample_type_colors
list_colors[["sample_identifier"]] = setNames(nm = sample_info$sample_identifier,
                                              sample_info$color)
# Cells order
column_order = subsobj@meta.data %>%
  dplyr::arrange(sample_type, sample_identifier) %>%
  rownames()
column_order = match(column_order, rownames(subsobj@meta.data))

# Heatmap
ha_top = HeatmapAnnotation(sample_type = subsobj$sample_type,
                           sample_identifier = subsobj$sample_identifier,
                           col = list(sample_type = list_colors[["sample_type"]],
                                      sample_identifier = list_colors[["sample_identifier"]]))

# Heatmap
ht = Heatmap(as.matrix(mat_expr),
             heatmap_legend_param = list(title = "Expression", at = c(0, 1), 
                                         labels = c("low", "high")),
             col = list_colors[["expression"]],
             top_annotation = ha_top,
             show_column_names = FALSE,
             column_order = column_order,
             column_gap = unit(2, "mm"),
             cluster_rows = FALSE,
             row_title = NULL,
             row_names_gp = grid::gpar(fontsize = 14, fontface = "plain"),
             use_raster = FALSE,
             show_heatmap_legend = TRUE,
             border = TRUE)

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom",
                     annotation_legend_side = "bottom")

HFSC

Settings

We load the HFSCs dataset :

sobj_hfsc = readRDS(paste0(data_dir, "/4_zoom/2_zoom_hfsc/hfsc_sobj.rds"))
sobj_hfsc
## An object of class Seurat 
## 15384 features across 1454 samples within 1 assay 
## Active assay: RNA (15384 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_24_tsne, RNA_pca_24_umap, harmony, harmony_24_umap, harmony_24_tsne

This is the projection name to visualize cells :

name2D = "harmony_24_tsne"

To represent results from differential expression, we load the analyses results :

list_results = readRDS(paste0(data_dir, "/4_zoom/2_zoom_hfsc/hfsc_list_results.rds"))

lapply(list_results, FUN = names)
## $cluster_0_8
## [1] "p_val"     "avg_logFC" "pct.1"     "pct.2"     "p_val_adj"
## 
## $cluster_2
## [1] "p_val"     "avg_logFC" "pct.1"     "pct.2"     "p_val_adj"
## 
## $cluster_1
## [1] "p_val"     "avg_logFC" "pct.1"     "pct.2"     "p_val_adj"
## 
## $cluster_3
## [1] "p_val"     "avg_logFC" "pct.1"     "pct.2"     "p_val_adj"

Figures

HFSCs on the full atlas :

sobj$is_hfsc = (colnames(sobj) %in% colnames(sobj_hfsc))

Seurat::DimPlot(sobj, reduction = name2D_atlas, pt.size = 0.000001,
                group.by = "is_hfsc", order = "TRUE") +
  ggplot2::scale_color_manual(values = c(color_markers[["HFSC"]], bg_color),
                              breaks = c(TRUE, FALSE)) +
  ggplot2::labs(title = "HFSCs",
                subtitle = paste0(ncol(sobj_hfsc), " cells")) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5, face = "bold"),
                 plot.subtitle = element_text(hjust = 0.5)) +
  Seurat::NoAxes() + Seurat::NoLegend()

KRT15 expression :

Seurat::FeaturePlot(sobj, reduction = name2D_atlas, pt.size = 0.000001,
                    features = "KRT15") +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() + Seurat::NoLegend()

Genes of interest :

genes = c("TGFB2", "ANGPTL7", "FGF18", "MGP", "EPCAM", "KRT75", "NOTCH3", "PTHLH")

plot_list = lapply(c(1:length(genes)), FUN = function(gene_id) {
  gene = genes[[gene_id]]
  
  sobj_hfsc$my_gene = Seurat::FetchData(sobj_hfsc, gene)[, 1] %>%
    aquarius::run_rescale(., new_min = 0, new_max = 10)
  
  Seurat::FeaturePlot(sobj_hfsc, features = "my_gene", reduction = name2D) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene,
                                   breaks = seq(0, 10, by = 2.5),
                                   labels = c("min", rep("", 3), "max")) +
    ggplot2::labs(title = gene) +
    ggplot2::theme(aspect.ratio = 1,
                   plot.title = element_text(hjust = 0.5, size = 17),
                   plot.subtitle = element_text(hjust = 0.5, size = 15),
                   legend.text = element_text(size = 15),
                   legend.position = "none") +
    Seurat::NoAxes()
})

plot_list
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

## 
## [[5]]

## 
## [[6]]

## 
## [[7]]

## 
## [[8]]

plot_list = lapply(c("IFITM3", "MIF", "DDIT4"), FUN = function(one_gene) {
  p = aquarius::plot_split_dimred(sobj_hfsc,
                                  reduction = name2D,
                                  split_by = "sample_type",
                                  color_by = one_gene,
                                  color_palette = viridis::viridis(n = 10),
                                  main_pt_size = 0.6,
                                  bg_pt_size = 0.6,
                                  order = TRUE,
                                  bg_color = "gray95")
  p = patchwork::wrap_plots(p, nrow = 1) +
    patchwork::plot_layout(guides = "collect") +
    ggplot2::theme(legend.position = "right") &
    ggplot2::theme(plot.subtitle = element_blank())
  return(p)
})

plot_list
## [[1]]

## 
## [[2]]

## 
## [[3]]

Project name :

# Random order
set.seed(1234)
rnd_order = sample(colnames(sobj_hfsc), replace = FALSE, size = ncol(sobj_hfsc))

# Extract coordinates
cells_coord = sobj_hfsc@reductions[[name2D]]@cell.embeddings %>%
  as.data.frame() %>%
  `colnames<-`(c("Dim1", "Dim2"))
cells_coord$project_name = sobj_hfsc$project_name
cells_coord = cells_coord[(rnd_order), ]

# Plot
ggplot2::ggplot(cells_coord, aes(x = Dim1, y = Dim2, col = project_name)) +
  ggplot2::geom_point(size = 1.2) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  ggplot2::theme_void() +
  ggplot2::theme(aspect.ratio = 1,
                 legend.position = "none")

Cluster :

Seurat::DimPlot(sobj_hfsc, reduction = name2D, pt.size = 1,
                group.by = "seurat_clusters", label = TRUE) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Heatmap with proportions :

cluster_markers = c("TGFB2", "ANGPTL7", "EPCAM", "KRT75", "NOTCH3", "PTHLH",
                    "percent.mt", "log_nCount_RNA")

## Bottom annotation : gene expression by cluster
ht_annot = Seurat::FetchData(sobj_hfsc, slot = "data", vars = cluster_markers) %>%
  as.data.frame()
ht_annot$clusters = sobj_hfsc$seurat_clusters
ht_annot = ht_annot %>%
  dplyr::group_by(clusters) %>%
  dplyr::summarise_all(funs('mean' = mean)) %>%
  as.data.frame() %>%
  dplyr::select(-clusters) %>%
  `colnames<-`(c(cluster_markers))

ha_bottom = ComplexHeatmap::HeatmapAnnotation(df = ht_annot,
                                              which = "column",
                                              show_legend = TRUE,
                                              col = setNames(nm = cluster_markers,
                                                             lapply(cluster_markers, FUN = color_fun)),
                                              annotation_name_side = "left")

## Right annotation : number of cells by dataset
ht_annot = table(sobj_hfsc$sample_identifier) %>%
  as.data.frame.table() %>%
  `colnames<-`(c("sample_identifier", "nb_cells")) %>%
  `rownames<-`(.$sample_identifier) %>%
  dplyr::select(-sample_identifier)

ha_right = ComplexHeatmap::HeatmapAnnotation(
  df = ht_annot,
  which = "row",
  show_legend = TRUE,
  annotation_name_side = "bottom",
  col = list(nb_cells  = circlize::colorRamp2(colors = RColorBrewer::brewer.pal(name = "Greys", n = 9),
                                              breaks = seq(from = range(ht_annot$nb_cells)[1],
                                                           to = range(ht_annot$nb_cells)[2],
                                                           length.out = 9))))

## Heatmap
ht = aquarius::plot_prop_heatmap(df = sobj_hfsc@meta.data[, c("sample_identifier", "seurat_clusters")],
                                 bottom_annotation = ha_bottom,
                                 right_annotation = ha_right,
                                 cluster_rows = TRUE,
                                 column_names_centered = TRUE,
                                 prop_margin = 1,
                                 row_names_gp = grid::gpar(names = sample_info$sample_identifier,
                                                           col = sample_info$color,
                                                           fontface = "bold"),
                                 row_title = "Sample",
                                 column_title = "Cluster")

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom")

Dotplot of DE genes in clusters 0 and 8, between HS and HD :

# features_oi = rownames(list_results$cluster_0_8)
# features_oi = features_oi[!grepl(features_oi, pattern = "^RP")]

subsobj = subset(sobj_hfsc, seurat_clusters %in% c(0,8))

features_oi = c("HLA-C", "HLA-B", "IFITM3", "MIF", "JUNB", "MARCKSL1",
                "LTBP2", "PDK4", "DDIT4", "S100A11")

Seurat::DotPlot(subsobj,
                assay = "RNA",
                features = features_oi,
                group.by = "sample_type",
                scale = FALSE) +
  ggplot2::coord_flip() +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(axis.title.x = element_blank(),
                 axis.title.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

Heatmap for clulster 0 and 8 :

# Matrix
mat_expr = Seurat::GetAssayData(subsobj)
mat_expr = mat_expr[features_oi, ]
mat_expr = Matrix::t(mat_expr)
mat_expr = dynutils::scale_quantile(mat_expr) # between 0 and 1
mat_expr = Matrix::t(mat_expr)
dim(mat_expr) # genes x cells
## [1]  10 631
## Colors
list_colors = list()

# Heatmap
list_colors[["expression"]] = rev(RColorBrewer::brewer.pal(name = "RdBu", n = 9))

# Sample annotation (top annotation)
list_colors[["sample_type"]] = sample_type_colors
list_colors[["sample_identifier"]] = setNames(nm = sample_info$sample_identifier,
                                              sample_info$color)
# list_colors[["seurat_clusters"]] = setNames(aquarius::gg_color_hue(length(levels(subsobj$seurat_clusters))),
#                                             nm = levels(subsobj$seurat_clusters))
# Cells order
column_order = subsobj@meta.data %>%
  dplyr::arrange(sample_type, sample_identifier) %>%
  rownames()
column_order = match(column_order, rownames(subsobj@meta.data))

# Heatmap
ha_top = HeatmapAnnotation(sample_type = subsobj$sample_type,
                           sample_identifier = subsobj$sample_identifier,
                           # clusters = subsobj$seurat_clusters,
                           col = list(sample_type = list_colors[["sample_type"]],
                                      sample_identifier = list_colors[["sample_identifier"]]
                                      # clusters = list_colors[["seurat_clusters"]]
                           ))

# Heatmap
ht = Heatmap(as.matrix(mat_expr),
             heatmap_legend_param = list(title = "Expression", at = c(0, 1), 
                                         labels = c("low", "high")),
             col = list_colors[["expression"]],
             top_annotation = ha_top,
             show_column_names = FALSE,
             column_order = column_order,
             column_gap = unit(2, "mm"),
             cluster_rows = FALSE,
             row_title = NULL,
             row_names_gp = grid::gpar(fontsize = 14, fontface = "plain"),
             use_raster = FALSE,
             show_heatmap_legend = TRUE,
             border = TRUE)

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom",
                     annotation_legend_side = "bottom")

Violin plot of IFITM3 :

table(subsobj$sample_type)
## 
##  HS  HD 
## 588  43
ifitm3_hs = subsobj@assays$RNA@data["IFITM3", subsobj$sample_type == "HS"]
ifitm3_hd = subsobj@assays$RNA@data["IFITM3", subsobj$sample_type == "HD"]
ifitm3_hs_VS_ifitm3_hd = stats::t.test(ifitm3_hs, ifitm3_hd)
ifitm3_hs_VS_ifitm3_hd
## 
##  Welch Two Sample t-test
## 
## data:  ifitm3_hs and ifitm3_hd
## t = 7.0204, df = 47.675, p-value = 7.081e-09
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.5509680 0.9933324
## sample estimates:
## mean of x mean of y 
##  1.775647  1.003497
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "IFITM3", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Violin plot of PDK4 :

table(subsobj$sample_type)
## 
##  HS  HD 
## 588  43
pdk4_hs = subsobj@assays$RNA@data["PDK4", subsobj$sample_type == "HS"]
pdk4_hd = subsobj@assays$RNA@data["PDK4", subsobj$sample_type == "HD"]
pdk4_hs_VS_pdk4_hd = stats::t.test(pdk4_hs, pdk4_hd)
pdk4_hs_VS_pdk4_hd
## 
##  Welch Two Sample t-test
## 
## data:  pdk4_hs and pdk4_hd
## t = -10.934, df = 43.02, p-value = 5.329e-14
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -2.523546 -1.737614
## sample estimates:
## mean of x mean of y 
## 0.1615592 2.2921393
Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = "PDK4", cols = sample_type_colors) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

IBL and ORS

Settings

We load the IBL + ORS dataset :

sobj_iblors = readRDS(paste0(data_dir, "/4_zoom/3_zoom_iblmors/iblmors_sobj.rds"))
sobj_iblors
## An object of class Seurat 
## 16701 features across 3532 samples within 1 assay 
## Active assay: RNA (16701 features, 2000 variable features)
##  6 dimensional reductions calculated: RNA_pca, RNA_pca_20_tsne, RNA_pca_20_umap, harmony, harmony_20_umap, harmony_20_tsne

This is the projection name to visualize cells :

name2D = "harmony_20_tsne"

To represent results from differential expression, we load the analyses results :

list_results = readRDS(paste0(data_dir, "/4_zoom/3_zoom_iblmors/iblmors_list_results.rds"))

lapply(list_results, FUN = names)
## $IBL_vs_ORS
## [1] "mark"        "enrichr_ibl" "enrichr_ors" "gsea"       
## 
## $cluster5_vs_ORS
## [1] "mark"       "enrichr_up" "enrichr_dn" "gsea"      
## 
## $IBL_HS_vs_HD
## [1] "mark"       "enrichr_hs" "enrichr_hd" "gsea"      
## 
## $ORS_HS_vs_HD
## [1] "mark"       "enrichr_hs" "enrichr_hd" "gsea"

Preparation

We defined cluster type :

cluster_type = table(sobj_iblors$cell_type, sobj_iblors$seurat_clusters) %>%
  prop.table(., margin = 2) %>%
  apply(., 2, which.max)
cluster_type = setNames(nm = names(cluster_type),
                        levels(sobj_iblors$cell_type)[cluster_type])

sobj_iblors$cluster_type = cluster_type[sobj_iblors$seurat_clusters]
sobj_iblors$cluster_type = factor(sobj_iblors$cluster_type,
                                  levels = levels(sobj_iblors$cell_type))

Figures

IBL + ORS on the full atlas :

sobj$cell_bc = colnames(sobj)
sobj_iblors$cell_bc = colnames(sobj_iblors)
sobj$is_iblors = dplyr::left_join(sobj@meta.data[, c("cell_bc", "percent.mt")],
                                  sobj_iblors@meta.data[, c("cell_bc", "cluster_type")],
                                  by = "cell_bc")[, "cluster_type"]

Seurat::DimPlot(sobj, reduction = name2D_atlas, pt.size = 0.000001,
                group.by = "is_iblors", order = "TRUE") +
  ggplot2::scale_color_manual(values = c(color_markers[c("IBL", "ORS")], bg_color),
                              breaks = c("IBL", "ORS", NA), na.value = bg_color) +
  ggplot2::labs(title = "IBL + ORS",
                subtitle = paste0(ncol(sobj_iblors), " cells")) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_text(hjust = 0.5, face = "bold"),
                 plot.subtitle = element_text(hjust = 0.5)) +
  Seurat::NoAxes() + Seurat::NoLegend()

Project name :

# Random order
set.seed(1234)
rnd_order = sample(colnames(sobj_iblors), replace = FALSE, size = ncol(sobj_iblors))

# Extract coordinates
cells_coord = sobj_iblors@reductions[[name2D]]@cell.embeddings %>%
  as.data.frame() %>%
  `colnames<-`(c("Dim1", "Dim2"))
cells_coord$project_name = sobj_iblors$project_name
cells_coord = cells_coord[(rnd_order), ]

# Plot
ggplot2::ggplot(cells_coord, aes(x = Dim1, y = Dim2, col = project_name)) +
  ggplot2::geom_point(size = 1.2) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  ggplot2::theme_void() +
  ggplot2::theme(aspect.ratio = 1,
                 legend.position = "none")

Cluster :

Seurat::DimPlot(sobj_iblors, reduction = name2D, pt.size = 1,
                group.by = "seurat_clusters", label = TRUE) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cluster type :

Seurat::DimPlot(sobj_iblors, reduction = name2D, pt.size = 1,
                group.by = "cluster_type", cols = color_markers) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cluster type split by sample type :

plot_list = aquarius::plot_split_dimred(sobj_iblors, reduction = name2D,
                                        group_by = "cluster_type",
                                        group_color = color_markers,
                                        split_by = "sample_type",
                                        bg_pt_size = 1, main_pt_size = 1,
                                        bg_color = bg_color)

patchwork::wrap_plots(plot_list) &
  Seurat::NoLegend()

DE genes between IBL and ORS :

mark = list_results$IBL_vs_ORS$mark
mark$gene_name = rownames(mark)
mark_label = rbind(
  # up-regulated in IBL
  mark %>% dplyr::top_n(., n = 20, wt = avg_logFC),
  # up-regulated in ORS
  mark %>% dplyr::top_n(., n = 20, wt = -avg_logFC),
  # representative and selective for IBL
  mark %>% dplyr::top_n(., n = 20, wt = (pct.1 - pct.2)),
  # representative and selective for ORS
  mark %>% dplyr::top_n(., n = 20, wt = -(pct.1 - pct.2))) %>%
  dplyr::distinct()
mark_label = mark_label[!grepl(rownames(mark_label), pattern = "^MT"), ]

ggplot2::ggplot(mark, aes(x = pct.1, y = pct.2, col = avg_logFC)) +
  ggplot2::geom_abline(slope = 1, intercept = 0, lty = 2) +
  ggplot2::geom_point() +
  ggrepel::geom_label_repel(data = mark_label, max.overlaps = Inf,
                            aes(x = pct.1, y = pct.2, label = gene_name),
                            col = "black", fill = NA, size = 3, label.size = NA) +
  ggplot2::labs(title = "Differentially expressed genes",
                subtitle = "between IBL and ORS") +
  ggplot2::scale_color_gradient2(low = aquarius::color_cnv[1],
                                 mid = aquarius::color_cnv[2],
                                 high = aquarius::color_cnv[3],
                                 midpoint = 0) +
  ggplot2::theme_classic() +
  ggplot2::theme(plot.title = element_text(hjust = 0.5),
                 plot.subtitle = element_text(hjust = 0.5))

GSEA for all genes, in IBL, between HS and HD :

# gs_oi = c("REACTOME_EXPORT_OF_VIRAL_RIBONUCLEOPROTEINS_FROM_NUCLEUS",
#           "GOBP_RESPONSE_TO_UV_C",
#           "GOBP_POSITIVE_REGULATION_OF_HISTONE_H3_K9_METHYLATION",
#           "GOBP_HISTONE_H3_K14_ACETYLATION",
#           "GOBP_MITOPHAGY")

list_results$IBL_HS_vs_HD$gsea@result %>%
  # dplyr::filter(ID %in% gs_oi) %>%
  dplyr::filter(pvalue <  0.05) %>%
  dplyr::top_n(., n = 200, wt = abs(NES)) %>%
  dplyr::mutate(too_long = ifelse(nchar(ID) > 60, yes = TRUE, no = FALSE)) %>%
  dplyr::mutate(ID = stringr::str_sub(ID, end = 60)) %>%
  dplyr::mutate(ID = ifelse(too_long, yes = paste0(ID, "..."), no = ID)) %>%
  aquarius::gsea_plot(show_legend = TRUE) +
  ggplot2::labs(title = "GSEA using all genes (count matrix)") +
  ggplot2::theme(plot.title = element_text(size = 20))

GSEA for all genes, in ORS, between HS and HD :

list_results$ORS_HS_vs_HD$gsea@result %>%
  # dplyr::filter(ID %in% gs_oi) %>%
  dplyr::filter(pvalue <  0.05) %>%
  dplyr::top_n(., n = 200, wt = abs(NES)) %>%
  dplyr::mutate(too_long = ifelse(nchar(ID) > 70, yes = TRUE, no = FALSE)) %>%
  dplyr::mutate(ID = stringr::str_sub(ID, end = 70)) %>%
  dplyr::mutate(ID = ifelse(too_long, yes = paste0(ID, "..."), no = ID)) %>%
  aquarius::gsea_plot(show_legend = TRUE) +
  ggplot2::labs(title = "GSEA using all genes (count matrix)") +
  ggplot2::theme(plot.title = element_text(size = 20))

Violin plot for IBL :

subsobj = subset(sobj_iblors, cluster_type == "IBL")

Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = c("DUSP1", "DDIT4", "MIF", "LGALS7", "ARF5", "S100A9"),
                cols = sample_type_colors, ncol = 3) &
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Violin plot for ORS :

subsobj = subset(sobj_iblors, cluster_type == "ORS")

Seurat::VlnPlot(subsobj, group.by = "sample_type",
                features = c("DUSP1", "CLDN1", "KLF6", "CTGF", "CCL2", "S100A9", "IFI27", "IFITM3"),
                cols = sample_type_colors, ncol = 4) &
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Split by sample :

Seurat::VlnPlot(subsobj, group.by = "sample_identifier",
                features = "IFI27", cols = sample_info$color) +
  ggplot2::theme(axis.title.x = element_blank(),
                 legend.position = "none")

Dotplot of DE genes in ORS, between cluster 5 and other ORS :

subsobj = subset(sobj_iblors, cluster_type == "ORS")
subsobj = subset(subsobj, seurat_clusters != 7)

# features_oi = list_results$cluster5_vs_ORS$mark %>%
#   dplyr::filter(p_val_adj < 0.05) %>%
#   dplyr::filter(abs(avg_logFC) > 0.5) %>%
#   dplyr::arrange(avg_logFC) %>%
#   rownames()

# features_oi = c("YBX3", "TXNIP", "KRT15", "NEAT1", "COL17A1", "FXYD3", "KRT14",
#                 "CXCL14", "MT2A", "MT1E", "FOS", "JUNB", "AQP3", "GLUL", "KLF5",
#                 "GSTM3", "ALDH3A1", "HLA-C", "LGALS7B", "SLC38A2", "EHF", "KLF3",
#                 "IL18", "CLEC2B", "IL20RB", "GPSM2", "DAAM1", "DUSP1", "KLF6",
#                 "ZFP36", "ATF3", "RHOB", "MT1X", "KLF4", "ETS2", "NFKBIZ", "ID1",
#                 "RNASET2", "HOPX", "WNT4", "POU3F1", "SPRY1", "AR", "THSD4", "PDGFC",
#                 "KRT31", "WFDC2", "SPINK5", "SLPI", "IL1R2", "PLAT", "TSC22D3",
#                 "KLF9", "WNT3", "FGFR3", "LAMB4", "IFI27", "DCN", "LY6D", "IGFBP3", "WFDC5",
#                 
#                 "S100A14", "TMSB10", "ACTG1", "ACTB", "CSTB", "APOE", "CALD1", "SOX4",
#                 "STMN1", "LMO4", "CEBPB", "TMEM45A", "CTSB", "GPX2", "C1QTNF12", "GJB6",
#                 "RBP1", "TPM1", "KRT17", "CALML3", "PTN", "DAPK2",
#                 "EGLN3", "FILIP1L", "FOXC1", "ADGRL3", "FST", "EFNB2", "SEMA5A",
#                 "FGFR1", "DACH1", "EGR2", "CLDN1", "CTGF", "DEFB1", "CARD18", "KRT6A",
#                 "S100A7", "KRT6B", "MGST1", "CHI3L1", "CCL19", "LGALS1", "CYP1B1", "VIM")

features_oi = c("YBX3", "TXNIP", "KRT14", "KRT15", "NEAT1",
                "FXYD3", "MT2A", "MT1E", "MT1X", "AQP3", "GLUL",
                # "HALLMARK_TNFA_SIGNALING_VIA_NFKB"
                "FOS", "JUNB", "DUSP1", "ZFP36", "NFKBIZ",
                "ATF3", "RHOB",  "ETS2", "IL18", "KLF4", "KLF6", "KLF9",
                "KLF3", "KLF5", "COL17A1", "THSD4", "WNT3", "WNT4", "SLPI", "PLAT",
                "LAMB4", "DCN", "SPINK5",
                "GSTM3", "ALDH3A1",  "LGALS7B", "SLC38A2", "EHF",  "CLEC2B",
                "IL20RB", "IL1R2", "IFI27", "CXCL14", "HLA-C", "GPSM2", "DAAM1",   "ID1",
                "RNASET2", "HOPX", "POU3F1", "SPRY1", "AR", "PDGFC",
                "WFDC2", "WFDC5", "TSC22D3", "FGFR3",  "LY6D", "IGFBP3", 
                
                # Other ORS
                "APOE", "CTSB", "CALD1", "SOX4",
                "STMN1", "LMO4", "CEBPB", "TMEM45A", "GPX2", "C1QTNF12", "GJB6",
                "KRT6A", "KRT17", "RBP1", "CALML3", "PTN", "DAPK2",
                "EGLN3", "FILIP1L", "ADGRL3", "FST", "EFNB2", "SEMA5A",
                "FGFR1", "EGR2", "CLDN1", "DEFB1", "CARD18", "MGST1")

Seurat::DotPlot(subsobj,
                assay = "RNA",
                features = features_oi,
                group.by = "sample_type",
                scale = FALSE) +
  ggplot2::coord_flip() +
  ggplot2::scale_color_gradientn(colors = aquarius::color_gene) +
  ggplot2::theme(axis.title.x = element_blank(),
                 axis.title.y = element_blank(),
                 axis.text.x = element_text(angle = 30, hjust = 1))

Heatmap for cluster 5 vs other ORS :

# Matrix
mat_expr = Seurat::GetAssayData(subsobj)
mat_expr = mat_expr[features_oi, ]
mat_expr = Matrix::t(mat_expr)
mat_expr = dynutils::scale_quantile(mat_expr) # between 0 and 1
mat_expr = Matrix::t(mat_expr)
dim(mat_expr) # genes x cells
## [1]   89 1793
## Colors
list_colors = list()
list_colors[["expression"]] = rev(RColorBrewer::brewer.pal(name = "RdBu", n = 9))
list_colors[["sample_type"]] = sample_type_colors
list_colors[["sample_identifier"]] = setNames(nm = sample_info$sample_identifier,
                                              sample_info$color)
list_colors[["seurat_clusters"]] = setNames(aquarius::gg_color_hue(length(levels(subsobj$seurat_clusters))),
                                            nm = levels(subsobj$seurat_clusters))
list_colors[["seurat_clusters"]] = list_colors[["seurat_clusters"]][unique(subsobj$seurat_clusters)]

# Cells order
column_order = subsobj@meta.data %>%
  dplyr::arrange(sample_type, sample_identifier) %>%
  rownames()
column_order = match(column_order, rownames(subsobj@meta.data))

# Annotation
ha_top = HeatmapAnnotation(sample_type = subsobj$sample_type,
                           sample_identifier = subsobj$sample_identifier,
                           clusters = subsobj$seurat_clusters,
                           col = list(sample_type = list_colors[["sample_type"]],
                                      sample_identifier = list_colors[["sample_identifier"]],
                                      clusters = list_colors[["seurat_clusters"]]))

# Heatmap
ht = Heatmap(as.matrix(mat_expr),
             heatmap_legend_param = list(title = "Expression", at = c(0, 1), 
                                         labels = c("low", "high")),
             col = list_colors[["expression"]],
             top_annotation = ha_top,
             # Cell grouping
             column_split = subsobj$sample_type %>% as.character(),
             cluster_columns = TRUE,
             column_title = NULL,
             show_column_dend = FALSE,
             show_column_names = FALSE,
             # Genes
             cluster_rows = FALSE,
             row_names_gp = grid::gpar(fontsize = 14, fontface = "plain"),
             # Style
             use_raster = FALSE,
             show_heatmap_legend = TRUE,
             border = TRUE)

ComplexHeatmap::draw(ht,
                     merge_legend = TRUE,
                     heatmap_legend_side = "bottom",
                     annotation_legend_side = "bottom")

Genes of interest :

genes = c("KRT16", "COL17A1", "DST", "KRT6B", "IL1R2", "WNT3",
          "IFI27", "CXCL14", "IGFBP3", "KRT15", "CD200")

plot_list = lapply(c(1:length(genes)), FUN = function(gene_id) {
  gene = genes[[gene_id]]
  
  sobj_iblors$my_gene = Seurat::FetchData(sobj_iblors, gene)[, 1] %>%
    aquarius::run_rescale(., new_min = 0, new_max = 10)
  
  Seurat::FeaturePlot(sobj_iblors, features = "my_gene", reduction = name2D, pt.size = 0.25) +
    ggplot2::scale_color_gradientn(colors = aquarius::color_gene,
                                   breaks = seq(0, 10, by = 2.5),
                                   labels = c("min", rep("", 3), "max")) +
    ggplot2::labs(title = gene) +
    ggplot2::theme(aspect.ratio = 1,
                   plot.title = element_text(hjust = 0.5, size = 17),
                   plot.subtitle = element_text(hjust = 0.5, size = 15),
                   legend.text = element_text(size = 15),
                   legend.position = "none") +
    Seurat::NoAxes()
})

plot_list
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

## 
## [[5]]

## 
## [[6]]

## 
## [[7]]

## 
## [[8]]

## 
## [[9]]

## 
## [[10]]

## 
## [[11]]

HFSCs to IBL and ORS

Settings

We load the merged dataset :

sobj_traj = readRDS(paste0(data_dir, "/4_zoom/4_zoom_hfsc_iblmors/hfsc_iblmors_sobj_traj_tinga.rds"))
sobj_traj
## An object of class Seurat 
## 17050 features across 4986 samples within 1 assay 
## Active assay: RNA (17050 features, 2000 variable features)
##  8 dimensional reductions calculated: RNA_pca, RNA_pca_18_tsne, RNA_pca_18_umap, harmony, harmony_18_umap, harmony_18_tsne, harmony_dm, harmony_dm_5_umap

This is the projection name to visualize cells :

name2D = "harmony_dm"

We load the trajectory object for visualisation purpose :

my_traj = readRDS(paste0(data_dir, "/4_zoom/4_zoom_hfsc_iblmors/hfsc_iblmors_my_traj_tinga.rds"))
class(my_traj)
## [1] "dynwrap::with_dimred"     "dynwrap::with_trajectory"
## [3] "dynwrap::data_wrapper"    "list"

Preparation

We defined cell type based on individual object :

sobj_iblors$cell_bc = colnames(sobj_iblors)
sobj_traj$cell_bc = colnames(sobj_traj)
sobj_traj$cluster_type = dplyr::left_join(sobj_traj@meta.data[, c("cell_bc", "percent.mt")],
                                          sobj_iblors@meta.data[, c("cell_bc", "cluster_type")],
                                          by = "cell_bc")[, "cluster_type"] %>% as.character()
sobj_traj$cluster_type = ifelse(colnames(sobj_traj) %in% colnames(sobj_hfsc),
                                yes = "HFSC",
                                no = sobj_traj$cluster_type) %>%
  as.factor()

Figures

Cells on the full atlas :

sobj$cell_bc = colnames(sobj)
sobj_traj$cell_bc = colnames(sobj_traj)
sobj$is_traj = dplyr::left_join(sobj@meta.data[, c("cell_bc", "percent.mt")],
                                sobj_traj@meta.data[, c("cell_bc", "cluster_type")],
                                by = "cell_bc")[, "cluster_type"]

Seurat::DimPlot(sobj, reduction = name2D_atlas, pt.size = 0.000001,
                group.by = "is_traj", order = levels(sobj_traj$cluster_type)) +
  ggplot2::scale_color_manual(values = c(color_markers[c("IBL", "ORS", "HFSC")], bg_color),
                              breaks = c("IBL", "ORS", "HFSC", NA), na.value = bg_color) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() + Seurat::NoLegend()

Project name :

# Random order
set.seed(1234)
rnd_order = sample(colnames(sobj_traj), replace = FALSE, size = ncol(sobj_traj))

# Extract coordinates
cells_coord = sobj_traj@reductions[[name2D]]@cell.embeddings %>%
  as.data.frame() %>%
  `colnames<-`(c("Dim1", "Dim2"))
cells_coord$project_name = sobj_traj$project_name
cells_coord = cells_coord[(rnd_order), ]

# Plot
ggplot2::ggplot(cells_coord, aes(x = Dim1, y = Dim2, col = project_name)) +
  ggplot2::geom_point(size = 1.2) +
  ggplot2::scale_color_manual(values = sample_info$color,
                              breaks = sample_info$project_name) +
  ggplot2::theme_void() +
  ggplot2::theme(aspect.ratio = 1,
                 legend.position = "none")

Cluster :

Seurat::DimPlot(sobj_traj, reduction = name2D, pt.size = 1,
                group.by = "seurat_clusters", label = TRUE) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Cluster type :

Seurat::DimPlot(sobj_traj, reduction = name2D, pt.size = 1,
                group.by = "cluster_type", cols = color_markers) +
  ggplot2::theme(aspect.ratio = 1) +
  Seurat::NoAxes() +
  Seurat::NoLegend()

Pseudotime :

Seurat::FeaturePlot(sobj_traj, reduction = name2D, pt.size = 0.5,
                    features = "pseudotime") +
  ggplot2::scale_color_gradientn(colors = viridis::viridis(n = 100)) +
  ggplot2::lims(x = range(sobj_traj@reductions[[name2D]]@cell.embeddings[, 1]),
                y = range(sobj_traj@reductions[[name2D]]@cell.embeddings[, 2])) +
  ggplot2::theme(aspect.ratio = 1,
                 plot.title = element_blank()) +
  Seurat::NoAxes()

Pseudotime with dynplot’s function :

dynplot::plot_dimred(trajectory = my_traj,
                     dimred = sobj_traj[[name2D]]@cell.embeddings,
                     # Cells
                     color_cells = 'pseudotime',
                     size_cells = 1.6,
                     border_radius_percentage = 0,
                     # Trajectory
                     plot_trajectory = TRUE,
                     color_trajectory = "none",
                     label_milestones = FALSE,
                     size_milestones = 0,
                     size_transitions = 1)

R Session

show
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.6 LTS
## 
## Matrix products: default
## BLAS:   /usr/local/lib/R/lib/libRblas.so
## LAPACK: /usr/local/lib/R/lib/libRlapack.so
## 
## locale:
## [1] C
## 
## attached base packages:
##  [1] parallel  stats4    grid      stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] org.Mm.eg.db_3.10.0   AnnotationDbi_1.48.0  IRanges_2.20.2       
##  [4] S4Vectors_0.24.4      Biobase_2.46.0        BiocGenerics_0.32.0  
##  [7] ComplexHeatmap_2.14.0 ggplot2_3.3.5         patchwork_1.1.2      
## [10] dplyr_1.0.7          
## 
## loaded via a namespace (and not attached):
##   [1] softImpute_1.4              graphlayouts_0.7.0         
##   [3] pbapply_1.4-2               lattice_0.20-41            
##   [5] haven_2.3.1                 dyndimred_1.0.3            
##   [7] vctrs_0.3.8                 usethis_2.0.1              
##   [9] dynwrap_1.2.1               blob_1.2.1                 
##  [11] survival_3.2-13             prodlim_2019.11.13         
##  [13] dynutils_1.0.5              later_1.3.0                
##  [15] DBI_1.1.1                   R.utils_2.11.0             
##  [17] SingleCellExperiment_1.8.0  rappdirs_0.3.3             
##  [19] uwot_0.1.8                  dqrng_0.2.1                
##  [21] jpeg_0.1-8.1                zlibbioc_1.32.0            
##  [23] pspline_1.0-18              pcaMethods_1.78.0          
##  [25] mvtnorm_1.1-1               htmlwidgets_1.5.4          
##  [27] GlobalOptions_0.1.2         future_1.22.1              
##  [29] UpSetR_1.4.0                laeken_0.5.2               
##  [31] leiden_0.3.3                clustree_0.4.3             
##  [33] lmds_0.1.0                  scater_1.14.6              
##  [35] irlba_2.3.3                 DEoptimR_1.0-9             
##  [37] tidygraph_1.1.2             Rcpp_1.0.9                 
##  [39] readr_2.0.2                 KernSmooth_2.23-17         
##  [41] carrier_0.1.0               promises_1.1.0             
##  [43] gdata_2.18.0                DelayedArray_0.12.3        
##  [45] limma_3.42.2                graph_1.64.0               
##  [47] RcppParallel_5.1.4          Hmisc_4.4-0                
##  [49] fs_1.5.2                    RSpectra_0.16-0            
##  [51] fastmatch_1.1-0             ranger_0.12.1              
##  [53] digest_0.6.25               png_0.1-7                  
##  [55] sctransform_0.2.1           cowplot_1.0.0              
##  [57] DOSE_3.12.0                 here_1.0.1                 
##  [59] TInGa_0.0.0.9000            dynplot_1.1.0              
##  [61] ggraph_2.0.3                pkgconfig_2.0.3            
##  [63] GO.db_3.10.0                DelayedMatrixStats_1.8.0   
##  [65] gower_0.2.1                 ggbeeswarm_0.6.0           
##  [67] iterators_1.0.12            DropletUtils_1.6.1         
##  [69] reticulate_1.26             clusterProfiler_3.14.3     
##  [71] SummarizedExperiment_1.16.1 circlize_0.4.15            
##  [73] beeswarm_0.4.0              GetoptLong_1.0.5           
##  [75] xfun_0.35                   bslib_0.3.1                
##  [77] zoo_1.8-10                  tidyselect_1.1.0           
##  [79] GA_3.2                      reshape2_1.4.4             
##  [81] purrr_0.3.4                 ica_1.0-2                  
##  [83] pcaPP_1.9-73                viridisLite_0.3.0          
##  [85] rtracklayer_1.46.0          rlang_1.0.2                
##  [87] hexbin_1.28.1               jquerylib_0.1.4            
##  [89] dyneval_0.9.9               glue_1.4.2                 
##  [91] waldo_0.3.1                 RColorBrewer_1.1-2         
##  [93] matrixStats_0.56.0          stringr_1.4.0              
##  [95] lava_1.6.7                  europepmc_0.3              
##  [97] DESeq2_1.26.0               recipes_0.1.17             
##  [99] labeling_0.3                httpuv_1.5.2               
## [101] class_7.3-17                BiocNeighbors_1.4.2        
## [103] DO.db_2.9                   annotate_1.64.0            
## [105] jsonlite_1.7.2              XVector_0.26.0             
## [107] bit_4.0.4                   mime_0.9                   
## [109] aquarius_0.1.5              Rsamtools_2.2.3            
## [111] gridExtra_2.3               gplots_3.0.3               
## [113] stringi_1.4.6               processx_3.5.2             
## [115] gsl_2.1-6                   bitops_1.0-6               
## [117] cli_3.0.1                   batchelor_1.2.4            
## [119] RSQLite_2.2.0               randomForest_4.6-14        
## [121] tidyr_1.1.4                 data.table_1.14.2          
## [123] rstudioapi_0.13             GenomicAlignments_1.22.1   
## [125] nlme_3.1-147                qvalue_2.18.0              
## [127] scran_1.14.6                locfit_1.5-9.4             
## [129] scDblFinder_1.1.8           listenv_0.8.0              
## [131] ggthemes_4.2.4              gridGraphics_0.5-0         
## [133] R.oo_1.24.0                 dbplyr_1.4.4               
## [135] TTR_0.24.2                  readxl_1.3.1               
## [137] lifecycle_1.0.1             timeDate_3043.102          
## [139] ggpattern_0.3.1             munsell_0.5.0              
## [141] cellranger_1.1.0            R.methodsS3_1.8.1          
## [143] proxyC_0.1.5                visNetwork_2.0.9           
## [145] caTools_1.18.0              codetools_0.2-16           
## [147] GenomeInfoDb_1.22.1         vipor_0.4.5                
## [149] lmtest_0.9-38               msigdbr_7.5.1              
## [151] htmlTable_1.13.3            triebeard_0.3.0            
## [153] lsei_1.2-0                  xtable_1.8-4               
## [155] ROCR_1.0-7                  BiocManager_1.30.10        
## [157] scatterplot3d_0.3-41        abind_1.4-5                
## [159] farver_2.0.3                parallelly_1.28.1          
## [161] RANN_2.6.1                  askpass_1.1                
## [163] GenomicRanges_1.38.0        RcppAnnoy_0.0.16           
## [165] tibble_3.1.5                ggdendro_0.1-20            
## [167] cluster_2.1.0               future.apply_1.5.0         
## [169] Seurat_3.1.5                dendextend_1.15.1          
## [171] Matrix_1.3-2                ellipsis_0.3.2             
## [173] prettyunits_1.1.1           lubridate_1.7.9            
## [175] ggridges_0.5.2              igraph_1.2.5               
## [177] RcppEigen_0.3.3.7.0         fgsea_1.12.0               
## [179] remotes_2.4.2               scBFA_1.0.0                
## [181] destiny_3.0.1               VIM_6.1.1                  
## [183] testthat_3.1.0              htmltools_0.5.2            
## [185] BiocFileCache_1.10.2        yaml_2.2.1                 
## [187] utf8_1.1.4                  plotly_4.9.2.1             
## [189] XML_3.99-0.3                ModelMetrics_1.2.2.2       
## [191] e1071_1.7-3                 foreign_0.8-76             
## [193] withr_2.5.0                 fitdistrplus_1.0-14        
## [195] BiocParallel_1.20.1         xgboost_1.4.1.1            
## [197] bit64_4.0.5                 foreach_1.5.0              
## [199] robustbase_0.93-9           Biostrings_2.54.0          
## [201] GOSemSim_2.13.1             rsvd_1.0.3                 
## [203] memoise_2.0.0               evaluate_0.18              
## [205] forcats_0.5.0               rio_0.5.16                 
## [207] geneplotter_1.64.0          tzdb_0.1.2                 
## [209] caret_6.0-86                ps_1.6.0                   
## [211] DiagrammeR_1.0.6.1          curl_4.3                   
## [213] fdrtool_1.2.15              fansi_0.4.1                
## [215] highr_0.8                   urltools_1.7.3             
## [217] xts_0.12.1                  GSEABase_1.48.0            
## [219] acepack_1.4.1               edgeR_3.28.1               
## [221] checkmate_2.0.0             scds_1.2.0                 
## [223] cachem_1.0.6                npsurv_0.4-0               
## [225] babelgene_22.3              rjson_0.2.20               
## [227] openxlsx_4.1.5              ggrepel_0.9.1              
## [229] clue_0.3-60                 rprojroot_2.0.2            
## [231] stabledist_0.7-1            tools_3.6.3                
## [233] sass_0.4.0                  nichenetr_1.1.1            
## [235] magrittr_2.0.1              RCurl_1.98-1.2             
## [237] proxy_0.4-24                car_3.0-11                 
## [239] ape_5.3                     ggplotify_0.0.5            
## [241] xml2_1.3.2                  httr_1.4.2                 
## [243] assertthat_0.2.1            rmarkdown_2.18             
## [245] boot_1.3-25                 globals_0.14.0             
## [247] R6_2.4.1                    Rhdf5lib_1.8.0             
## [249] nnet_7.3-14                 RcppHNSW_0.2.0             
## [251] progress_1.2.2              genefilter_1.68.0          
## [253] statmod_1.4.34              gtools_3.8.2               
## [255] shape_1.4.6                 HDF5Array_1.14.4           
## [257] BiocSingular_1.2.2          rhdf5_2.30.1               
## [259] splines_3.6.3               AUCell_1.8.0               
## [261] carData_3.0-4               colorspace_1.4-1           
## [263] generics_0.1.0              base64enc_0.1-3            
## [265] dynfeature_1.0.0            smoother_1.1               
## [267] gridtext_0.1.1              pillar_1.6.3               
## [269] tweenr_1.0.1                sp_1.4-1                   
## [271] ggplot.multistats_1.0.0     rvcheck_0.1.8              
## [273] GenomeInfoDbData_1.2.2      plyr_1.8.6                 
## [275] gtable_0.3.0                zip_2.2.0                  
## [277] knitr_1.41                  latticeExtra_0.6-29        
## [279] biomaRt_2.42.1              fastmap_1.1.0              
## [281] ADGofTest_0.3               copula_1.0-0               
## [283] doParallel_1.0.15           vcd_1.4-8                  
## [285] babelwhale_1.0.1            openssl_1.4.1              
## [287] scales_1.1.1                backports_1.2.1            
## [289] ipred_0.9-12                enrichplot_1.6.1           
## [291] hms_1.1.1                   ggforce_0.3.1              
## [293] Rtsne_0.15                  shiny_1.7.1                
## [295] numDeriv_2016.8-1.1         polyclip_1.10-0            
## [297] lazyeval_0.2.2              Formula_1.2-3              
## [299] tsne_0.1-3                  crayon_1.3.4               
## [301] MASS_7.3-54                 pROC_1.16.2                
## [303] viridis_0.5.1               dynparam_1.0.0             
## [305] rpart_4.1-15                zinbwave_1.8.0             
## [307] compiler_3.6.3              ggtext_0.1.0
LS0tCnRpdGxlOiAiSFMgcHJvamVjdCIKc3VidGl0bGU6ICJGaWd1cmVzIgphdXRob3I6ICJBdWRyZXkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVZLSVtLSVkJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKLS0tCgo8c3R5bGU+CmJvZHkgewp0ZXh0LWFsaWduOiBqdXN0aWZ5fQo8L3N0eWxlPgoKPCEtLSBBdXRvbWF0aWNhbGx5IGNvbXB1dGVzIGFuZCBwcmludHMgaW4gdGhlIG91dHB1dCB0aGUgcnVubmluZyB0aW1lIGZvciBhbnkgY29kZSBjaHVuayAtLT4KYGBge3IsIGVjaG89RkFMU0V9CiMgaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vcm1hcmtkb3duL2lzc3Vlcy8xNDUzCmhvb2tzID0ga25pdHI6OmtuaXRfaG9va3MkZ2V0KCkKaG9va19mb2xkYWJsZSA9IGZ1bmN0aW9uKHR5cGUpIHsKICBmb3JjZSh0eXBlKQogIGZ1bmN0aW9uKHgsIG9wdGlvbnMpIHsKICAgIHJlcyA9IGhvb2tzW1t0eXBlXV0oeCwgb3B0aW9ucykKICAgIAogICAgaWYgKGlzRkFMU0Uob3B0aW9uc1tbcGFzdGUwKCJmb2xkXyIsIHR5cGUpXV0pKSByZXR1cm4ocmVzKQogICAgCiAgICBwYXN0ZTAoCiAgICAgICI8ZGV0YWlscz48c3VtbWFyeT4iLCAic2hvdyIsICI8L3N1bW1hcnk+XG5cbiIsCiAgICAgIHJlcywKICAgICAgIlxuXG48L2RldGFpbHM+IgogICAgKQogIH0KfQprbml0cjo6a25pdF9ob29rcyRzZXQoCiAgb3V0cHV0ID0gaG9va19mb2xkYWJsZSgib3V0cHV0IiksCiAgcGxvdCA9IGhvb2tfZm9sZGFibGUoInBsb3QiKSwKICB0aW1lX2l0ID0gbG9jYWwoewogICAgbm93ID0gTlVMTAogICAgZnVuY3Rpb24oYmVmb3JlLCBvcHRpb25zKSB7CiAgICAgIGlmIChvcHRpb25zJHRpbWVfaXQpIHsKICAgICAgICBpZiAoYmVmb3JlKSB7CiAgICAgICAgICBub3cgPD0gU3lzLnRpbWUoKQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXMgPSBkaWZmdGltZShTeXMudGltZSgpLCBub3csIHVuaXRzID0gInNlY3MiKQogICAgICAgICAgcGFzdGUoIihUaW1lIHRvIHJ1biA6Iiwgcm91bmQocmVzLCBkaWdpdHMgPSAyKSwgInMpIikKICAgICAgICB9CiAgICAgIH0KICAgIH0KICB9KQopCmBgYAoKPCEtLSBTZXQgZGVmYXVsdCBwYXJhbWV0ZXJzIGZvciBhbGwgY2h1bmtzIC0tPgpgYGB7ciwgc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0Kc2V0LnNlZWQoMTMzN0wpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgIyBkaXNwbGF5IGNvZGUKICAgICAgICAgICAgICAgICAgICAgICMgZGlzcGxheSBjaHVuayBvdXRwdXQKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZvbGRfb3V0cHV0ID0gRkFMU0UsICMgdXNlZnVsIGZvciBzZXNzaW9uSW5mbygpCiAgICAgICAgICAgICAgICAgICAgICBmb2xkX3Bsb3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBmaWd1cmUgc2V0dGluZ3MKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICdjZW50ZXInLAogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuaGVpZ2h0ID0gMTUsCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgc29tZXRoaW5nIGFib3V0IHNlZWQsIGNodW5rIGFuZCBSbWFya2Rvd24gY29tcGlsYXRpb24KICAgICAgICAgICAgICAgICAgICAgICMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzk0MTcwMDMvbG9uZy12ZWN0b3JzLW5vdC1zdXBwb3J0ZWQteWV0LWVycm9yLWluLXJtZC1idXQtbm90LWluLXItc2NyaXB0CiAgICAgICAgICAgICAgICAgICAgICAjIGNhY2hlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGNhY2hlLmxhenkgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICMgYWRkIHJ1bnRpbWUgYWZ0ZXIgY2h1bmsKICAgICAgICAgICAgICAgICAgICAgIHRpbWVfaXQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIyBzYXZlIGZpZ3VyZXMgaW4gUERGIGluIGEgc2VwYXJhdGUgZm9sZGVyCiAgICAgICAgICAgICAgICAgICAgICBkZXYgPSBjKCdwbmcnLCAncGRmJyksICMgdGlmZiBvciBwZGYgYWxvbmUgcmVuZGVycyBiYWQgaW4gaHRtbAogICAgICAgICAgICAgICAgICAgICAgIyBkcGkgPSAzMDAsCiAgICAgICAgICAgICAgICAgICAgICBmaWcucGF0aCA9ICJmaWd1cmVzX2RldGFpbC8iLAogICAgICAgICAgICAgICAgICAgICAgcGRmLm9wdGlvbnMoZW5jb2RpbmcgPSAiSVNPTGF0aW45LmVuYyIpKQpgYGAKCgpUaGlzIGZpbGUgaXMgdXNlZCB0byBwcmVwYXJlIHRoZSBmaWd1cmVzIGZvciB0aGUgcGFwZXIuCgpgYGB7ciBsaWJyYXJ5fQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KG9yZy5NbS5lZy5kYikKCi5saWJQYXRocygpCmBgYAoKCiMgUHJlcGFyYXRpb24KCkhlcmUgYXJlIHRoZSBmb2xkZXJzIHdoZXJlIGFuYWx5emVzIGFyZSBzdG9yZWQgOgoKYGBge3IgbG9jYXRpb25zfQpkYXRhX2RpciA9ICIuLy4uIgpsaXN0LmZpbGVzKGRhdGFfZGlyKQpgYGAKCgpXZSBsb2FkIHRoZSBkYXRhc2V0IGNvbnRhaW5pbmcgYWxsIGNlbGxzIDoKCmBgYHtyIGxvYWRfYWxsX3NvYmp9CnNvYmogPSByZWFkUkRTKHBhc3RlMChkYXRhX2RpciwgIi8zX2NvbWJpbmVkL2hzX2hkX3NvYmoucmRzIikpCnNvYmoKYGBgCgpUaGVzZSBhcmUgYWxsIHRoZSBzYW1wbGVzIGFuYWx5emVkIDoKCmBgYHtyIHNhbXBsZV9pbmZvLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDN9CnNhbXBsZV9pbmZvID0gcmVhZFJEUyhwYXN0ZTAoZGF0YV9kaXIsICIvMV9tZXRhZGF0YS9oc19oZF9zYW1wbGVfaW5mby5yZHMiKSkKCiMgTmIgY2VsbHMgYnkgZGF0YXNldAp0b19wbG90ID0gdGFibGUoc29iaiRzYW1wbGVfaWRlbnRpZmllcikgJT4lCiAgYXMuZGF0YS5mcmFtZS50YWJsZSguLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICU+JQogIGBjb2xuYW1lczwtYChjKCJzYW1wbGVfaWRlbnRpZmllciIsICJuYl9jZWxscyIpKSAlPiUKICBkcGx5cjo6bGVmdF9qb2luKHggPSAuLCB5ID0gc2FtcGxlX2luZm8sIGJ5ID0gInNhbXBsZV9pZGVudGlmaWVyIikgCgojIHBhdGNod29yawpwbG90X2xpc3QgPSBhcXVhcml1czo6ZmlnX3Bsb3RfZ2IodG9fcGxvdCwgdGl0bGUgPSAiQXZhaWxhYmxlIGRhdGFzZXRzIikKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCkgKwogIHBhdGNod29yazo6cGxvdF9sYXlvdXQoZGVzaWduID0gIkFcbkIiLCBoZWlnaHRzID0gYygwLjEsNSkpICYKICBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTUpKQpgYGAKClRoZXNlIGFyZSB0aGUgY3VzdG9tIGNvbG9ycyBmb3IgY2VsbCBwb3B1bGF0aW9ucyA6CgpgYGB7ciBjb2xvcl9tYXJrZXJzLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDEsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpjb2xvcl9tYXJrZXJzID0gcmVhZFJEUyhwYXN0ZTAoZGF0YV9kaXIsICIvMV9tZXRhZGF0YS9oc19oZF9jb2xvcl9tYXJrZXJzLnJkcyIpKQpjb2xvcl9tYXJrZXJzID0gY29sb3JfbWFya2Vyc1tuYW1lcyhjb2xvcl9tYXJrZXJzKSAhPSAibWVsYW5vY3l0ZXMiXQpvcnNfY29sb3IgPSBjb2xvcl9tYXJrZXJzWyJPUlMiXQpjb2xvcl9tYXJrZXJzWyJPUlMiXSA9IGNvbG9yX21hcmtlcnNbIklGRSJdIApjb2xvcl9tYXJrZXJzWyJJRkUiXSA9IG9yc19jb2xvcgpjb2xvcl9tYXJrZXJzWyJCIGNlbGxzIl0gPSAiY2hvY29sYXRlMyIKcm0ob3JzX2NvbG9yKQoKZGF0YS5mcmFtZShjZWxsX3R5cGUgPSBuYW1lcyhjb2xvcl9tYXJrZXJzKSwKICAgICAgICAgICBjb2xvciA9IHVubGlzdChjb2xvcl9tYXJrZXJzKSkgJT4lCiAgZ2dwbG90Mjo6Z2dwbG90KC4sIGFlcyh4ID0gY2VsbF90eXBlLCB5ID0gMCwgZmlsbCA9IGNlbGxfdHlwZSkpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHBjaCA9IDIxLCBzaXplID0gNSkgKwogIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjb2xvcl9tYXJrZXJzKSwgYnJlYWtzID0gbmFtZXMoY29sb3JfbWFya2VycykpICsKICBnZ3Bsb3QyOjp0aGVtZV9jbGFzc2ljKCkgKwogIGdncGxvdDI6OnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgYW5nbGUgPSAyMCkpCmBgYAoKV2UgZGVmaW5lIGN1c3RvbSBjb2xvcnMgZm9yIHNhbXBsZSB0eXBlIDoKCmBgYHtyIHNhbXBsZV90eXBlX2NvbG9ycywgZmlnLndpZHRoID0gMywgZmlnLmhlaWdodCA9IDAuNzUsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpzYW1wbGVfdHlwZV9jb2xvcnMgPSBzZXROYW1lcyhubSA9IGxldmVscyhzYW1wbGVfaW5mbyRzYW1wbGVfdHlwZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIiNDNTVGNDAiLCAiIzJDNzhFNiIpKQoKZGF0YS5mcmFtZShjZWxsX3R5cGUgPSBuYW1lcyhzYW1wbGVfdHlwZV9jb2xvcnMpLAogICAgICAgICAgIGNvbG9yID0gdW5saXN0KHNhbXBsZV90eXBlX2NvbG9ycykpICU+JQogIGdncGxvdDI6OmdncGxvdCguLCBhZXMoeCA9IGNlbGxfdHlwZSwgeSA9IDAsIGZpbGwgPSBjZWxsX3R5cGUpKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChwY2ggPSAyMSwgc2l6ZSA9IDUpICsKICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3Qoc2FtcGxlX3R5cGVfY29sb3JzKSwgYnJlYWtzID0gbmFtZXMoc2FtcGxlX3R5cGVfY29sb3JzKSkgKwogIGdncGxvdDI6OnRoZW1lX2NsYXNzaWMoKSArCiAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKV2Ugc2V0IGEgYmFja2dyb3VuZCBjb2xvciA6CgpgYGB7ciBiZ19jb2xvcn0KYmdfY29sb3IgPSAiZ3JheTk0IgpgYGAKCgpUaGlzIGlzIHRoZSBjb3JyZXNwb25kZW5jZSBiZXR3ZWVuIGNlbGwgdHlwZXMgYW5kIGNlbGwgZmFtaWxpZXMsIGFuZCBjdXN0b20gY29sb3JzIHRvIGNvbG9yIGNlbGxzIGJ5IGNlbGwgZmFtaWx5IDoKCmBgYHtyIGNlbGxfZmFtaWx5fQpjdXN0b21fb3JkZXJfY2VsbF90eXBlID0gZGF0YS5mcmFtZSgKICBjZWxsX3R5cGUgPSBuYW1lcyhjb2xvcl9tYXJrZXJzKSwKICBjZWxsX2ZhbWlseSA9IGMocmVwKCJpbW11bmUgY2VsbHMiLCA1KSwKICAgICAgICAgICAgICAgICAgcmVwKCJtYXRyaXgiLCA1KSwKICAgICAgICAgICAgICAgICAgcmVwKCJub24gbWF0cml4IiwgNSkpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKY3VzdG9tX29yZGVyX2NlbGxfdHlwZSRjZWxsX3R5cGUgPSBmYWN0b3IoY3VzdG9tX29yZGVyX2NlbGxfdHlwZSRjZWxsX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGN1c3RvbV9vcmRlcl9jZWxsX3R5cGUkY2VsbF90eXBlKQpyb3duYW1lcyhjdXN0b21fb3JkZXJfY2VsbF90eXBlKSA9IGN1c3RvbV9vcmRlcl9jZWxsX3R5cGUkY2VsbF90eXBlCgpmYW1pbHlfY29sb3IgPSBjKCJpbW11bmUgY2VsbHMiID0gInNsYXRlYmx1ZTEiLAogICAgICAgICAgICAgICAgICJtYXRyaXgiID0gIm1lZGl1bXNlYWdyZWVuIiwKICAgICAgICAgICAgICAgICAibm9uIG1hdHJpeCIgPSAiZmlyZWJyaWNrMyIpCmBgYAoKV2UgbG9hZCBtYXJrZXJzIHRvIGRpc3BsYXkgb24gYSBkb3RwbG90IHRvIGFzc2VzcyBjZWxsIHR5cGUgYW5ub3RhdGlvbiA6CgpgYGB7ciBkb3RwbG90X21hcmtlcnN9CmRvdHBsb3RfbWFya2VycyA9IHJlYWRSRFMocGFzdGUwKGRhdGFfZGlyLCAiLzFfbWV0YWRhdGEvaHNfaGRfZG90cGxvdF9tYXJrZXJzLnJkcyIpKQpkb3RwbG90X21hcmtlcnMgPSBkb3RwbG90X21hcmtlcnNbbmFtZXMoZG90cGxvdF9tYXJrZXJzKSAhPSAibWVsYW5vY3l0ZXMiXQpsZW5ndGhzKGRvdHBsb3RfbWFya2VycykKYGBgCgpDdXN0b20gZnVuY3Rpb25zIHRvIGRpc3BsYXkgZ2VuZSBleHByZXNzaW9uIG9uIHRoZSBoZWF0bWFwIDoKCmBgYHtyIGNvbG9yX2Z1biwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmNvbG9yX2Z1biA9IGZ1bmN0aW9uKG9uZV9nZW5lKSB7CiAgZ2VuZV9yYW5nZSA9IHJhbmdlKGh0X2Fubm90Wywgb25lX2dlbmVdKQogIGdlbmVfcGFsZXR0ZSA9IGNpcmNsaXplOjpjb2xvclJhbXAyKGNvbG9ycyA9IGMoIiNGRkZGRkYiLCBhcXVhcml1czo6Y29sb3JfZ2VuZVstMV0pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gZ2VuZV9yYW5nZVsxXSwgdG8gPSBnZW5lX3JhbmdlWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gbGVuZ3RoKGFxdWFyaXVzOjpjb2xvcl9nZW5lKSkpCiAgcmV0dXJuKGdlbmVfcGFsZXR0ZSkKfQpgYGAKCgojIEFsbCBzYW1wbGVzCgojIyBTZXR0aW5ncwoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBuYW1lIHRvIHZpc3VhbGl6ZSBjZWxscyA6CgpgYGB7ciBhbGxfc29ial9uYW1lMkR9Cm5hbWUyRCA9ICJoYXJtb255XzM4X3RzbmUiCm5hbWUyRF9hdGxhcyA9IG5hbWUyRApgYGAKCiMjIFByZXBhcmF0aW9uCgpXZSBtYWtlIGEgbG93IHJlc29sdXRpdmUgY2x1c3RlcmluZyBmb3IgdGhlIGhlYXRtYXAgOgoKYGBge3IgY2x1c3Rlcl9hbGx9CnNvYmogPSBTZXVyYXQ6OkZpbmRDbHVzdGVycyhzb2JqLCByZXNvbHV0aW9uID0gMC40KQoKbGVuZ3RoKGxldmVscyhzb2JqJHNldXJhdF9jbHVzdGVycykpCmBgYAoKCldlIGRlZmluZSBjbHVzdGVyIHR5cGUgYW5kIGNsdXN0ZXIgZmFtaWx5IDoKCmBgYHtyIGNsdXN0ZXJfdHlwZV9mYW1pbHlfYWxsLCBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gNX0KY2x1c3Rlcl90eXBlID0gdGFibGUoc29iaiRjZWxsX3R5cGUsIHNvYmokc2V1cmF0X2NsdXN0ZXJzKSAlPiUKICBwcm9wLnRhYmxlKC4sIG1hcmdpbiA9IDIpICU+JQogIGFwcGx5KC4sIDIsIHdoaWNoLm1heCkKY2x1c3Rlcl90eXBlID0gc2V0TmFtZXMobm0gPSBuYW1lcyhjbHVzdGVyX3R5cGUpLAogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMoc29iaiRjZWxsX3R5cGUpW2NsdXN0ZXJfdHlwZV0pCgpzb2JqJGNsdXN0ZXJfdHlwZSA9IGNsdXN0ZXJfdHlwZVtzb2JqJHNldXJhdF9jbHVzdGVyc10Kc29iaiRjbHVzdGVyX3R5cGUgPSBmYWN0b3Ioc29iaiRjbHVzdGVyX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxldmVscyhzb2JqJGNlbGxfdHlwZSkpCnNvYmokY2x1c3Rlcl9mYW1pbHkgPSBjdXN0b21fb3JkZXJfY2VsbF90eXBlW3NvYmokY2x1c3Rlcl90eXBlLCAiY2VsbF9mYW1pbHkiXQpzb2JqJGNsdXN0ZXJfZmFtaWx5ID0gZmFjdG9yKHNvYmokY2x1c3Rlcl9mYW1pbHksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbmFtZXMoZmFtaWx5X2NvbG9yKSkKYGBgCgoKIyMgRmlndXJlcwoKUHJvamVjdCBuYW1lIDoKCmBgYHtyIGZpZzFfc2FtcGxlX2lkZW50aWZpZXIsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQojIFJhbmRvbSBvcmRlcgpzZXQuc2VlZCgxMjM0KQpybmRfb3JkZXIgPSBzYW1wbGUoY29sbmFtZXMoc29iaiksIHJlcGxhY2UgPSBGQUxTRSwgc2l6ZSA9IG5jb2woc29iaikpCgojIEV4dHJhY3QgY29vcmRpbmF0ZXMKY2VsbHNfY29vcmQgPSBzb2JqQHJlZHVjdGlvbnNbW25hbWUyRF1dQGNlbGwuZW1iZWRkaW5ncyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgYGNvbG5hbWVzPC1gKGMoIkRpbTEiLCAiRGltMiIpKQpjZWxsc19jb29yZCRwcm9qZWN0X25hbWUgPSBzb2JqJHByb2plY3RfbmFtZQpjZWxsc19jb29yZCA9IGNlbGxzX2Nvb3JkWyhybmRfb3JkZXIpLCBdCgojIFBsb3QKZ2dwbG90Mjo6Z2dwbG90KGNlbGxzX2Nvb3JkLCBhZXMoeCA9IERpbTEsIHkgPSBEaW0yLCBjb2wgPSBwcm9qZWN0X25hbWUpKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChzaXplID0gMC41KSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHNhbXBsZV9pbmZvJGNvbG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpICsKICBnZ3Bsb3QyOjp0aGVtZV92b2lkKCkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCkNsdXN0ZXIgOgoKYGBge3IgZmlnMV9jbHVzdGVyLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0KU2V1cmF0OjpEaW1QbG90KHNvYmosIHJlZHVjdGlvbiA9IG5hbWUyRCwgcHQuc2l6ZSA9IDAuNCwKICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVFJVRSkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBTZXVyYXQ6Ok5vTGVnZW5kKCkKYGBgCgpDZWxsIHR5cGUgYW5ub3RhdGlvbiA6CgpgYGB7ciBmaWcxX2NlbGxfdHlwZSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDR9ClNldXJhdDo6RGltUGxvdChzb2JqLCByZWR1Y3Rpb24gPSBuYW1lMkQsIHB0LnNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJjZWxsX3R5cGUiLCBjb2xzID0gY29sb3JfbWFya2VycykgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBTZXVyYXQ6Ok5vTGVnZW5kKCkKYGBgCgpDbHVzdGVyIGZhbWlseSBhbm5vdGF0aW9uIDoKCmBgYHtyIGZpZzFfY2x1c3Rlcl9mYW1pbHksIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA2fQpTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJELCBwdC5zaXplID0gMC41LAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2x1c3Rlcl9mYW1pbHkiLCBjb2xzID0gZmFtaWx5X2NvbG9yKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKwogIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCkNlbGwgdHlwZSBhbm5vdGF0aW9uIHNwbGl0IGJ5IGNvbmRpdGlvbiA6CgpgYGB7ciBmaWcxX2NlbGxfdHlwZV9zcGxpdCwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDV9CnBsb3RfbGlzdCA9IGFxdWFyaXVzOjpwbG90X3NwbGl0X2RpbXJlZChzb2JqLCByZWR1Y3Rpb24gPSBuYW1lMkQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieSA9ICJjZWxsX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfY29sb3IgPSBjb2xvcl9tYXJrZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRfYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRfY29sb3IgPSBzYW1wbGVfdHlwZV9jb2xvcnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZ19jb2xvciA9IGJnX2NvbG9yKQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCkgJgogIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCkdlbmUgZXhwcmVzc2lvbiB0byBhc3Nlc3MgYW5ub3RhdGlvbiA6CgpgYGB7ciBmaWcxX2dlbmVfZmFtaWx5LCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0KZ2VuZXMgPSBjKCJQVFBSQyIsICJNU1gyIiwgIktSVDE0IikKbmFtZXMoZ2VuZXMpID0gYygiaW1tdW5lIGNlbGxzIiwgIm1hdHJpeCBjZWxscyIsICJub24tbWF0cml4IGNlbGxzIikKCnBsb3RfbGlzdCA9IGxhcHBseShjKDE6bGVuZ3RoKGdlbmVzKSksIEZVTiA9IGZ1bmN0aW9uKGdlbmVfaWQpIHsKICBnZW5lID0gZ2VuZXNbW2dlbmVfaWRdXQogIHBvcCA9IG5hbWVzKGdlbmVzKVtnZW5lX2lkXQogIAogIHNvYmokbXlfZ2VuZSA9IFNldXJhdDo6RmV0Y2hEYXRhKHNvYmosIGdlbmUpWywgMV0gJT4lCiAgICBhcXVhcml1czo6cnVuX3Jlc2NhbGUoLiwgbmV3X21pbiA9IDAsIG5ld19tYXggPSAxMCkKICAKICBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gIm15X2dlbmUiLCByZWR1Y3Rpb24gPSBuYW1lMkQpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAsIGJ5ID0gMi41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJtaW4iLCByZXAoIiIsIDMpLCAibWF4IikpICsKICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBnZW5lKSArIAogICAgIyBzdWJ0aXRsZSA9IHBvcCkgKwogICAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNyksCiAgICAgICAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTUpLAogICAgICAgICAgICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgU2V1cmF0OjpOb0F4ZXMoKQp9KQoKcGxvdF9saXN0CmBgYAoKQmFycGxvdCBieSBjbHVzdGVyIGZhbWlseSA6CgpgYGB7ciBmaWcxX2JhcnBsb3RfZmFtaWx5LCBmaWcud2lkdGggPSA1LjUsIGZpZy5oZWlnaHQgPSA0LjV9CnF1YW50aWYgPSB0YWJsZShzb2JqJHNhbXBsZV9pZGVudGlmaWVyKSAlPiUKICBhcy5kYXRhLmZyYW1lLnRhYmxlKCkgJT4lCiAgYGNvbG5hbWVzPC1gKGMoIlNhbXBsZSIsICJuYl9jZWxscyIpKQoKYXF1YXJpdXM6OnBsb3RfYmFycGxvdChkZiA9IHRhYmxlKHNvYmokc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb2JqJGNsdXN0ZXJfZmFtaWx5KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmRhdGEuZnJhbWUudGFibGUoKSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgIGBjb2xuYW1lczwtYChjKCJTYW1wbGUiLCAiQ2VsbCBUeXBlIiwgIk51bWJlciIpKSwKICAgICAgICAgICAgICAgICAgICAgICB4ID0gIlNhbXBsZSIsIHkgPSAiTnVtYmVyIiwgZmlsbCA9ICJDZWxsIFR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCgpKSArCiAgZ2dwbG90Mjo6Z2VvbV9sYWJlbChkYXRhID0gcXVhbnRpZiwgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gLmRhdGEkU2FtcGxlLCB5ID0gMS4wNSwgbGFiZWwgPSAuZGF0YSRuYl9jZWxscyksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbC5zaXplID0gMCwgc2l6ZSA9IDUpICsKICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB1bmxpc3QoZmFtaWx5X2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBuYW1lcyhmYW1pbHlfY29sb3IpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ2VsbCBGYW1pbHkiKSArCiAgZ2dwbG90Mjo6c2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxLCBieSA9IDAuMjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwYXN0ZTAoc2VxKDAsIDEwMCwgYnkgPSAyNSksIHNlcCA9ICIgJSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBnZ3Bsb3QyOjpleHBhbnNpb24oYWRkID0gYygwLCAwLjA1KSkpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JheSIpLAogICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKSGVhdG1hcCBvZiBjbHVzdGVyIHByb3BvcnRpb24gYnkgc2FtcGxlIDoKCmBgYHtyIGZpZzFfaGVhdG1hcF9wcm9wLCBmaWcud2lkdGggPSAxNSwgZmlnLmhlaWdodCA9IDYsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpncm91cF9ieSA9ICJzZXVyYXRfY2x1c3RlcnMiCgpjbHVzdGVyX2J5X3NhbXBsZSA9IHRhYmxlKHNvYmokc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgc29iakBtZXRhLmRhdGFbLCBncm91cF9ieV0pICU+JQogIHByb3AudGFibGUobWFyZ2luID0gMSkgJT4lCiAgYXMubWF0cml4KCkKCiMjIFJlcHJlc2VudGF0aXZlIG1hcmtlcnMKY2x1c3Rlcl9tYXJrZXJzID0gYygiUFRQUkMiLCAiQ0QzRSIsICJBSUYxIiwgIk1TWDIiLCAiRElPMiIsICJHUFgyIiwgIktSVDE2IikKaHRfYW5ub3QgPSBTZXVyYXQ6OkdldEFzc2F5RGF0YShzb2JqLCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKVtjbHVzdGVyX21hcmtlcnMsIF0gJT4lCiAgTWF0cml4Ojp0KCkgJT4lIGFzLmRhdGEuZnJhbWUoKQpodF9hbm5vdCRjbHVzdGVycyA9IHNvYmpAbWV0YS5kYXRhWywgZ3JvdXBfYnldCmh0X2Fubm90ID0gaHRfYW5ub3QgJT4lCiAgZHBseXI6Omdyb3VwX2J5KGNsdXN0ZXJzKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlX2FsbChmdW5zKCdtZWFuJyA9IG1lYW4pKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtY2x1c3RlcnMpICU+JQogIGBjb2xuYW1lczwtYChjKGNsdXN0ZXJfbWFya2VycykpCgojIyBCb3R0b20gYW5ub3RhdGlvbiA6IGF2ZXJhZ2UgZ2VuZSBleHByZXNzaW9uCmhhX2JvdHRvbSA9IENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwQW5ub3RhdGlvbihkZiA9IGh0X2Fubm90LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2ggPSAiY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dfbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBzZXROYW1lcyhubSA9IGNsdXN0ZXJfbWFya2VycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShjbHVzdGVyX21hcmtlcnMsIEZVTiA9IGNvbG9yX2Z1bikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAicmlnaHQiKQoKIyMgUmlnaHQgYW5ub3RhdGlvbiA6IG51bWJlciBvZiBjZWxscyBieSBkYXRhc2V0Cmh0X2Fubm90ID0gdGFibGUoc29iaiRzYW1wbGVfaWRlbnRpZmllcikgJT4lCiAgYXMuZGF0YS5mcmFtZS50YWJsZSgpICU+JQogIGBjb2xuYW1lczwtYChjKCJzYW1wbGVfaWRlbnRpZmllciIsICJuYl9jZWxscyIpKSAlPiUKICBgcm93bmFtZXM8LWAoLiRzYW1wbGVfaWRlbnRpZmllcikgJT4lCiAgZHBseXI6OnNlbGVjdCgtc2FtcGxlX2lkZW50aWZpZXIpCgpoYV9yaWdodCA9IENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwQW5ub3RhdGlvbigKICBkZiA9IGh0X2Fubm90LAogIHdoaWNoID0gInJvdyIsCiAgc2hvd19sZWdlbmQgPSBUUlVFLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gInRvcCIsCiAgY29sID0gbGlzdChuYl9jZWxscyAgPSBjaXJjbGl6ZTo6Y29sb3JSYW1wMihjb2xvcnMgPSBSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobmFtZSA9ICJHcmV5cyIsIG4gPSA5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcShmcm9tID0gcmFuZ2UoaHRfYW5ub3QkbmJfY2VsbHMpWzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gcmFuZ2UoaHRfYW5ub3QkbmJfY2VsbHMpWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSA5KSkpKQoKIyMgTGVmdCBhbm5vdGF0aW9uIDogZ2VuZGVyCmhhX2xlZnQgPSBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcEFubm90YXRpb24oCiAgZ2VuZGVyID0gc2FtcGxlX2luZm8kZ2VuZGVyLAogIHdoaWNoID0gInJvdyIsCiAgc2hvd19sZWdlbmQgPSBUUlVFLAogIGFubm90YXRpb25fbmFtZV9zaWRlID0gImJvdHRvbSIsCiAgY29sID0gbGlzdChnZW5kZXIgPSBzZXROYW1lcyhubSA9IGMoIkYiLCAiTSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygibGlnaHRjeWFuMyIsICJuYXZ5Ymx1ZSIpKSkpCgojIyBUb3AgYW5ub3RhdGlvbiA6IG1haW4gY2VsbCB0eXBlIGluIHRoaXMgY2x1c3RlcgpodF9hbm5vdCA9IHRhYmxlKHNvYmokc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgc29iakBtZXRhLmRhdGFbLCBncm91cF9ieV0pICU+JQogIHByb3AudGFibGUobWFyZ2luID0gMSkgJT4lCiAgYXMubWF0cml4KCkKCmh0X2Fubm90ID0gdGFibGUoc29iaiRjZWxsX3R5cGUsCiAgICAgICAgICAgICAgICAgc29iakBtZXRhLmRhdGFbLCBncm91cF9ieV0pICU+JQogIHByb3AudGFibGUoLiwgbWFyZ2luID0gMikgJT4lCiAgYXBwbHkoLiwgMiwgd2hpY2gubWF4KQpodF9hbm5vdCA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gbmFtZXMoaHRfYW5ub3QpLAogICAgICAgICAgICAgICAgICAgICAgY2VsbF90eXBlID0gbmFtZXMoY29sb3JfbWFya2VycylbaHRfYW5ub3RdLAogICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpodF9hbm5vdCA9IGRwbHlyOjpsZWZ0X2pvaW4oaHRfYW5ub3QsIGN1c3RvbV9vcmRlcl9jZWxsX3R5cGUsIGJ5ID0gImNlbGxfdHlwZSIpICU+JQogICMgU2ltcGxpZmljYXRpb24gZm9yIG1hdHJpeAogIGRwbHlyOjptdXRhdGUoY2VsbF90eXBlID0gaWZlbHNlKGNlbGxfdHlwZSAlaW4lIGMoIm1lZHVsbGEiLCAiY29ydGV4IiwgImN1dGljbGUiKSwgeWVzID0gImhhaXIgc2hhZnQiLCBubyA9IGNlbGxfdHlwZSkpICU+JQogICMgU2ltcGxpZmljYXRpb24gZm9yIFQgY2VsbHMKICBkcGx5cjo6bXV0YXRlKGNlbGxfdHlwZSA9IGlmZWxzZShjZWxsX3R5cGUgJWluJSBjKCJDRDQgVCBjZWxscyIsICJDRDggVCBjZWxscyIpLCB5ZXMgPSAiVCBjZWxscyIsIG5vID0gY2VsbF90eXBlKSkgJT4lCiAgIyBTaW1wbGlmaWNhdGlvbiBmb3IgQVBDCiAgZHBseXI6Om11dGF0ZShjZWxsX3R5cGUgPSBpZmVsc2UoY2VsbF90eXBlICVpbiUgYygiTGFuZ2VyaGFucyBjZWxscyIsICJtYWNyb3BoYWdlcyIpLCB5ZXMgPSAiQVBDIiwgbm8gPSBjZWxsX3R5cGUpKSAlPiUKICAjIEFkZCBjb2xvcgogIGRwbHlyOjptdXRhdGUoY29sb3IgPSBhcy5jaGFyYWN0ZXIoY29sb3JfbWFya2Vyc1tjZWxsX3R5cGVdKSkgJT4lCiAgZHBseXI6Om11dGF0ZShjb2xvciA9IGlmZWxzZShjZWxsX3R5cGUgPT0gImhhaXIgc2hhZnQiLCB5ZXMgPSAiI0ZGQjZDMSIsIG5vID0gY29sb3IpKSAlPiUKICBkcGx5cjo6bXV0YXRlKGNvbG9yID0gaWZlbHNlKGNlbGxfdHlwZSA9PSAiVCBjZWxscyIsIHllcyA9ICIjOEE2RUU2Iiwgbm8gPSBjb2xvcikpICU+JQogIGRwbHlyOjptdXRhdGUoY29sb3IgPSBpZmVsc2UoY2VsbF90eXBlID09ICJBUEMiLCB5ZXMgPSAiIzlDQUE0QiIsIG5vID0gY29sb3IpKQoKaGFfdG9wID0gQ29tcGxleEhlYXRtYXA6OkhlYXRtYXBBbm5vdGF0aW9uKAogIGNlbGxfdHlwZSA9IGh0X2Fubm90JGNlbGxfdHlwZSwKICAjIGNlbGxfZmFtaWx5ID0gaHRfYW5ub3QkY2VsbF9mYW1pbHksCiAgd2hpY2ggPSAiY29sdW1uIiwKICBzaG93X2xlZ2VuZCA9IFRSVUUsCiAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAibGVmdCIsCiAgY29sID0gbGlzdChjZWxsX3R5cGUgPSBzZXROYW1lcyhubSA9IGh0X2Fubm90JGNlbGxfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGh0X2Fubm90JGNvbG9yKQogICAgICAgICAgICAgIywgY2VsbF9mYW1pbHkgPSBmYW1pbHlfY29sb3IKICApKQoKIyMgQXNzZW1ibGUgaGVhdG1hcApodCA9IENvbXBsZXhIZWF0bWFwOjpIZWF0bWFwKGNsdXN0ZXJfYnlfc2FtcGxlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9ICJQcm9wb3J0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gYygiIzIxNjZBQyIsICIjRjdGN0Y3IiwgIiNCMjE4MkIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBib3R0b21fYW5ub3RhdGlvbiA9IGhhX2JvdHRvbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodF9hbm5vdGF0aW9uID0gaGFfcmlnaHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9hbm5vdGF0aW9uID0gaGFfbGVmdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGhhX3RvcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X3RpdGxlID0gIlNhbXBsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3JpZDo6Z3BhcihuYW1lcyA9IHNhbXBsZV9pbmZvJHNhbXBsZV9pZGVudGlmaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gc2FtcGxlX2luZm8kY29sb3IsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX3RpdGxlID0gIkNsdXN0ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbl9uYW1lc19jZW50ZXJlZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93X25hbWVzX3NpZGUgPSAibGVmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uX25hbWVzX3NpZGUgPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfcm90ID0gMCkKCiMjIERyYXcgIQpDb21wbGV4SGVhdG1hcDo6ZHJhdyhodCwgbWVyZ2VfbGVnZW5kcyA9IFRSVUUpCmBgYAoKRG90cGxvdCA6CgpgYGB7ciBmaWcxX2RvdHBsb3QsIGZpZy53aWR0aCA9IDYuNSwgZmlnLmhlaWdodCA9IDcsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwbG90X2xpc3QgPSBhcXVhcml1czo6cGxvdF9kb3RwbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VycyA9IGMoIlBUUFJDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0QzRSIsICJDRDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDNFIiwgIkNEOEEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDIwNyIsICJDUFZMIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSRU0yIiwgIk1TUjEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDRDc5QSIsICJDRDc5QiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIktSVDMyIiwgIktSVDM1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS1JUMzEiLCAiUFJSOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJBTUJJIiwgIkFETEgxQTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLUlQ3MSIsICJLUlQ3MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRPUDJBIiwgIk1DTTUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLUlQxNiIsICJLUlQ2QyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIktSVDE1IiwgIkdQWDIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTUElOSzUiLCAiTFk2RCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRJTzIiLCAiVENFQUwyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQ0xNUCIsICJQUEFSRyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIsIGNvbHVtbl9uYW1lID0gImNlbGxfdHlwZSIsIG5iX2hsaW5lID0gMCkgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogIGdncGxvdDI6OnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIsCiAgICAgICAgICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLCA0KSwgImNtIikpCgpwID0gZ2dwbG90Mjo6Z2dwbG90KGN1c3RvbV9vcmRlcl9jZWxsX3R5cGUsIGFlcyh4ID0gY2VsbF90eXBlLCB5ID0gMCkpICsKICBnZ3Bsb3QyOjpnZW9tX3BvaW50KHNpemUgPSAwKSArCiAgZ2dwbG90Mjo6Z2VvbV9zZWdtZW50KGFlcyh4ID0gMC41LCB4ZW5kID0gNS41LCB5ID0gMCwgeWVuZCA9IDApLCBzaXplID0gNiwgY29sID0gZmFtaWx5X2NvbG9yWyJpbW11bmUgY2VsbHMiXSkgKwogIGdncGxvdDI6Omdlb21fc2VnbWVudChhZXMoeCA9IDUuNSwgeGVuZCA9IDEwLjUsIHkgPSAwLCB5ZW5kID0gMCksIHNpemUgPSA2LCBjb2wgPSBmYW1pbHlfY29sb3JbIm1hdHJpeCJdKSArCiAgZ2dwbG90Mjo6Z2VvbV9zZWdtZW50KGFlcyh4ID0gMTAuNSwgeGVuZCA9IDE1LjUsIHkgPSAwLCB5ZW5kID0gMCksIHNpemUgPSA2LCBjb2wgPSBmYW1pbHlfY29sb3JbIm5vbiBtYXRyaXgiXSkgKwogIGdncGxvdDI6OnNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwwKSkgKwogIGdncGxvdDI6OnRoZW1lX2NsYXNzaWMoKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksCiAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KHJlcCgwLCA0KSwgImNtIikpCgpwbG90X2xpc3QgPSBwYXRjaHdvcms6OndyYXBfcGxvdHMocGxvdF9saXN0LCBwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsIGhlaWdodHMgPSBjKDI1LCAxKSkKcGxvdF9saXN0CgoKCgoKYGBgCgoKIyBJbW11bmUgY2VsbHMKCiMjIFNldHRpbmdzCgpXZSBsb2FkIHRoZSBpbW11bmUgY2VsbHMgZGF0YXNldCA6CgpgYGB7ciBzb2JqX2ljfQpzb2JqX2ljID0gcmVhZFJEUyhwYXN0ZTAoZGF0YV9kaXIsICIvNF96b29tLzFfem9vbV9pbW11bmUvaW1tdW5lX2NlbGxzX3NvYmoucmRzIikpCnNvYmpfaWMKYGBgCgoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBuYW1lIHRvIHZpc3VhbGl6ZSBjZWxscyA6CgpgYGB7ciBzb2JqX25hbWUyRF9pY30KbmFtZTJEID0gImhhcm1vbnlfMjBfdHNuZSIKYGBgCgpUbyByZXByZXNlbnQgcmVzdWx0cyBmcm9tIGRpZmZlcmVudGlhbCBleHByZXNzaW9uLCB3ZSBsb2FkIHRoZSBhbmFseXNlcyByZXN1bHRzIDoKCmBgYHtyIGxpc3RfcmVzdWx0c19pY30KbGlzdF9yZXN1bHRzID0gcmVhZFJEUyhwYXN0ZTAoZGF0YV9kaXIsICIvNF96b29tLzFfem9vbV9pbW11bmUvaW1tdW5lX2NlbGxzX2xpc3RfcmVzdWx0cy5yZHMiKSkKCmxhcHBseShsaXN0X3Jlc3VsdHMsIEZVTiA9IG5hbWVzKQpgYGAKCgojIyBQcmVwYXJhdGlvbgoKV2UgZGVmaW5lZCBjbHVzdGVyIHR5cGUgYW5kIGNsdXN0ZXIgZmFtaWx5IDoKCmBgYHtyIGNsdXN0ZXJfdHlwZV9mYW1pbHlfaWMsIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA1fQpjbHVzdGVyX3R5cGUgPSB0YWJsZShzb2JqX2ljJGNlbGxfdHlwZSwgc29ial9pYyRzZXVyYXRfY2x1c3RlcnMpICU+JQogIHByb3AudGFibGUoLiwgbWFyZ2luID0gMikgJT4lCiAgYXBwbHkoLiwgMiwgd2hpY2gubWF4KQpjbHVzdGVyX3R5cGUgPSBzZXROYW1lcyhubSA9IG5hbWVzKGNsdXN0ZXJfdHlwZSksCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyhzb2JqX2ljJGNlbGxfdHlwZSlbY2x1c3Rlcl90eXBlXSkKCnNvYmpfaWMkY2x1c3Rlcl90eXBlID0gY2x1c3Rlcl90eXBlW3NvYmpfaWMkc2V1cmF0X2NsdXN0ZXJzXQpzb2JqX2ljJGNsdXN0ZXJfdHlwZSA9IGZhY3Rvcihzb2JqX2ljJGNsdXN0ZXJfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGV2ZWxzKHNvYmpfaWMkY2VsbF90eXBlKSkKc29ial9pYyRjbHVzdGVyX2ZhbWlseSA9IGN1c3RvbV9vcmRlcl9jZWxsX3R5cGVbc29ial9pYyRjbHVzdGVyX3R5cGUsICJjZWxsX2ZhbWlseSJdCnNvYmpfaWMkY2x1c3Rlcl9mYW1pbHkgPSBmYWN0b3Ioc29ial9pYyRjbHVzdGVyX2ZhbWlseSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBuYW1lcyhmYW1pbHlfY29sb3IpKQpgYGAKCgojIyBGaWd1cmVzCgpDb250cm9sIGNlbGxzIG9uIHRoZSBmdWxsIGF0bGFzIDoKCmBgYHtyIGZpZ19pY19sb2NhdGlvbiwgZmlnLndpZHRoID0gMiwgZmlnLmhlaWdodCA9IDJ9CnNvYmokaXNfaW1tdW5lID0gKGNvbG5hbWVzKHNvYmopICVpbiUgY29sbmFtZXMoc29ial9pYykpCgpTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJEX2F0bGFzLCBwdC5zaXplID0gMC4wMDAwMDEsCiAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJpc19pbW11bmUiLCBvcmRlciA9ICJUUlVFIikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGZhbWlseV9jb2xvcltbImltbXVuZSBjZWxscyJdXSwgYmdfY29sb3IpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKFRSVUUsIEZBTFNFKSkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiSW1tdW5lIGNlbGxzIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKG5jb2woc29ial9pYyksICIgY2VsbHMiKSkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKClZpb2xpbiBwbG90IG9mIElMMUIgaW4gbWFjcm9waGFnZXMgOgoKYGBge3IgZmlnX2ljX21hY19pbDFiLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0Kc3Vic29iaiA9IHN1YnNldChzb2JqX2ljLCBzZXVyYXRfY2x1c3RlcnMgPT0gMikKdGFibGUoc3Vic29iaiRzYW1wbGVfdHlwZSkKCmlsMWJfaHMgPSBzdWJzb2JqQGFzc2F5cyRSTkFAZGF0YVsiSUwxQiIsIHN1YnNvYmokc2FtcGxlX3R5cGUgPT0gIkhTIl0KaWwxYl9oZCA9IHN1YnNvYmpAYXNzYXlzJFJOQUBkYXRhWyJJTDFCIiwgc3Vic29iaiRzYW1wbGVfdHlwZSA9PSAiSEQiXQppbDFiX2hzX1ZTX2lsMWJfaGQgPSBzdGF0czo6dC50ZXN0KGlsMWJfaHMsIGlsMWJfaGQpCmlsMWJfaHNfVlNfaWwxYl9oZAoKU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIklMMUIiLCBjb2xzID0gc2FtcGxlX3R5cGVfY29sb3JzKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpTcGxpdCBieSBzYW1wbGUgOgoKYGBge3IgZmlnX2ljX21hY19pbDFiX3NwbGl0LCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV9pZGVudGlmaWVyIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIklMMUIiLCBjb2xzID0gc2FtcGxlX2luZm8kY29sb3IpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKClZpb2xpbiBwbG90IG9mIElMMUIgaW4gbWFjcm9waGFnZXMgOgoKYGBge3IgZmlnX2ljX21hY19pbDYsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQppbDZfaHMgPSBzdWJzb2JqQGFzc2F5cyRSTkFAZGF0YVsiSUw2Iiwgc3Vic29iaiRzYW1wbGVfdHlwZSA9PSAiSFMiXQppbDZfaGQgPSBzdWJzb2JqQGFzc2F5cyRSTkFAZGF0YVsiSUw2Iiwgc3Vic29iaiRzYW1wbGVfdHlwZSA9PSAiSEQiXQppbDZfaHNfVlNfaWw2X2hkID0gc3RhdHM6OnQudGVzdChpbDZfaHMsIGlsNl9oZCkKaWw2X2hzX1ZTX2lsNl9oZAoKU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIklMNiIsIGNvbHMgPSBzYW1wbGVfdHlwZV9jb2xvcnMpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKClZpb2xpbiBwbG90IG9mIElMMUIgaW4gbWFjcm9waGFnZXMgOgoKYGBge3IgZmlnX2ljX21hY190bmYsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQpzdWJzb2JqID0gc3Vic2V0KHNvYmpfaWMsIHNldXJhdF9jbHVzdGVycyA9PSAyKQp0YWJsZShzdWJzb2JqJHNhbXBsZV90eXBlKQoKdG5mX2hzID0gc3Vic29iakBhc3NheXMkUk5BQGRhdGFbIlRORiIsIHN1YnNvYmokc2FtcGxlX3R5cGUgPT0gIkhTIl0KdG5mX2hkID0gc3Vic29iakBhc3NheXMkUk5BQGRhdGFbIlRORiIsIHN1YnNvYmokc2FtcGxlX3R5cGUgPT0gIkhEIl0KdG5mX2hzX1ZTX3RuZl9oZCA9IHN0YXRzOjp0LnRlc3QodG5mX2hzLCB0bmZfaGQpCnRuZl9oc19WU190bmZfaGQKClNldXJhdDo6VmxuUGxvdChzdWJzb2JqLCBncm91cC5ieSA9ICJzYW1wbGVfdHlwZSIsCiAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJUTkYiLCBjb2xzID0gc2FtcGxlX3R5cGVfY29sb3JzKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpTcGxpdCBieSBzYW1wbGUgOgoKYGBge3IgZmlnX2ljX21hY190bmZfc3BsaXQsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA0fQpTZXVyYXQ6OlZsblBsb3Qoc3Vic29iaiwgZ3JvdXAuYnkgPSAic2FtcGxlX2lkZW50aWZpZXIiLAogICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiVE5GIiwgY29scyA9IHNhbXBsZV9pbmZvJGNvbG9yKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpWaW9saW4gcGxvdCBvZiBHWk1BIGluIENENCBUIGNlbGxzIDoKCmBgYHtyIGZpZ19pY190NF9nem1hLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0Kc3Vic29iaiA9IHN1YnNldChzb2JqX2ljLCBzZXVyYXRfY2x1c3RlcnMgJWluJSBjKDAsMTApKQp0YWJsZShzdWJzb2JqJHNhbXBsZV90eXBlKQoKZ3ptYV9ocyA9IHN1YnNvYmpAYXNzYXlzJFJOQUBkYXRhWyJHWk1BIiwgc3Vic29iaiRzYW1wbGVfdHlwZSA9PSAiSFMiXQpnem1hX2hkID0gc3Vic29iakBhc3NheXMkUk5BQGRhdGFbIkdaTUEiLCBzdWJzb2JqJHNhbXBsZV90eXBlID09ICJIRCJdCmd6bWFfaHNfVlNfZ3ptYV9oZCA9IHN0YXRzOjp0LnRlc3QoZ3ptYV9ocywgZ3ptYV9oZCkKZ3ptYV9oc19WU19nem1hX2hkCgpTZXVyYXQ6OlZsblBsb3Qoc3Vic29iaiwgZ3JvdXAuYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiR1pNQSIsIGNvbHMgPSBzYW1wbGVfdHlwZV9jb2xvcnMpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCldlIHJlcHJlc2VudCBzb21lIGdlbmVzIHNwbGl0IGJ5IHNhbXBsZSB0eXBlIDoKCmBgYHtyIGZpZ19pY19nZW5lX3NwbGl0LCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDZ9CnBsb3RfbGlzdCA9IGxhcHBseShjKCJJTDFCIiwgIkdaTUEiLCAiSUZORyIsICJJTDE3QSIpLCBGVU4gPSBmdW5jdGlvbihvbmVfZ2VuZSkgewogIHAgPSBhcXVhcml1czo6cGxvdF9zcGxpdF9kaW1yZWQoc29ial9pYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZHVjdGlvbiA9IG5hbWUyRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwbGl0X2J5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gb25lX2dlbmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9wYWxldHRlID0gYygiZ3JheTcwIiwgIiNGREJCODQiLCAiI0VGNjU0OCIsICIjN0YwMDAwIiwgImJsYWNrIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWluX3B0X3NpemUgPSAwLjYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZ19wdF9zaXplID0gMC42LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXIgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmdfY29sb3IgPSAiZ3JheTk1IikKICBwID0gcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHAsIG5yb3cgPSAxKSArCiAgICBwYXRjaHdvcms6OnBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikgKwogICAgZ2dwbG90Mjo6dGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgJgogICAgZ2dwbG90Mjo6dGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKICByZXR1cm4ocCkKfSkKCnBhdGNod29yazo6d3JhcF9wbG90cyhwbG90X2xpc3QsIG5jb2wgPSAyKQpgYGAKCkJhcnBsb3QgYnkgY2x1c3RlciB0eXBlIDoKCmBgYHtyIGZpZ19pY19iYXJwbG90LCBmaWcud2lkdGggPSA1LjUsIGZpZy5oZWlnaHQgPSA0LjV9CnF1YW50aWYgPSB0YWJsZShzb2JqX2ljJHNhbXBsZV9pZGVudGlmaWVyKSAlPiUKICBhcy5kYXRhLmZyYW1lLnRhYmxlKCkgJT4lCiAgYGNvbG5hbWVzPC1gKGMoIlNhbXBsZSIsICJuYl9jZWxscyIpKQoKYXF1YXJpdXM6OnBsb3RfYmFycGxvdChkZiA9IHRhYmxlKHNvYmpfaWMkc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb2JqX2ljJGNsdXN0ZXJfdHlwZSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICBhcy5kYXRhLmZyYW1lLnRhYmxlKCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICBgY29sbmFtZXM8LWAoYygiU2FtcGxlIiwgIkNlbGwgVHlwZSIsICJOdW1iZXIiKSksCiAgICAgICAgICAgICAgICAgICAgICAgeCA9ICJTYW1wbGUiLCB5ID0gIk51bWJlciIsIGZpbGwgPSAiQ2VsbCBUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKCkpICsKICBnZ3Bsb3QyOjpnZW9tX2xhYmVsKGRhdGEgPSBxdWFudGlmLCBpbmhlcml0LmFlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSAuZGF0YSRTYW1wbGUsIHkgPSA1MCArIC5kYXRhJG5iX2NlbGxzLCBsYWJlbCA9IC5kYXRhJG5iX2NlbGxzKSwKICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnNpemUgPSAwLCBzaXplID0gNSkgKwogIGdncGxvdDI6OnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHVubGlzdChjb2xvcl9tYXJrZXJzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBuYW1lcyhjb2xvcl9tYXJrZXJzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNlbGwgVHlwZSIpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImxpZ2h0Z3JheSIpLAogICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKRG90cGxvdCBvZiBERSBnZW5lcyBmb3IgbWFjcm9waGFnZXMgOgoKYGBge3IgZmlnX2ljX2RvdHBsb3RfbWFjcm9waGFnZXMsIGZpZy5oZWlnaHQgPSAzLjUsIGZpZy53aWR0aCA9IDV9CnN1YnNvYmogPSBzdWJzZXQoc29ial9pYywgY2x1c3Rlcl90eXBlID09ICJtYWNyb3BoYWdlcyIpCmZlYXR1cmVzX29pID0gYygiSExBLURRQTIiLCAiSExBLURQQTEiLCAiSExBLURSQjUiLAogICAgICAgICAgICAgICAgIkhMQS1BIiwgIkhMQS1DIiwgIkIyTSIsCiAgICAgICAgICAgICAgICAiQzFRQSIsICJDMVFCIiwgIkMxUUMiKQoKU2V1cmF0OjpEb3RQbG90KHN1YnNvYmosCiAgICAgICAgICAgICAgICBhc3NheSA9ICJSTkEiLAogICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBmZWF0dXJlc19vaSwKICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIHNjYWxlID0gRkFMU0UpICsKICBnZ3Bsb3QyOjpjb29yZF9mbGlwKCkgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSkgKwogIGdncGxvdDI6OnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKYGBgCgpIZWF0bWFwIGZvciBtYWNyb3BoYWdlcyA6CgpgYGB7ciBmaWdfaWNfaGVhdG1hcF9tYWNyb3BoYWdlcywgZmlnLndpZHRoID0gNSwgZmlnLmhlaWdodCA9IDQsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIE1hdHJpeAptYXRfZXhwciA9IFNldXJhdDo6R2V0QXNzYXlEYXRhKHN1YnNvYmopCm1hdF9leHByID0gbWF0X2V4cHJbZmVhdHVyZXNfb2ksIF0KbWF0X2V4cHIgPSBNYXRyaXg6OnQobWF0X2V4cHIpCm1hdF9leHByID0gZHludXRpbHM6OnNjYWxlX3F1YW50aWxlKG1hdF9leHByKSAjIGJldHdlZW4gMCBhbmQgMQptYXRfZXhwciA9IE1hdHJpeDo6dChtYXRfZXhwcikKZGltKG1hdF9leHByKSAjIGdlbmVzIHggY2VsbHMKIyMgQ29sb3JzCmxpc3RfY29sb3JzID0gbGlzdCgpCgojIEhlYXRtYXAKbGlzdF9jb2xvcnNbWyJleHByZXNzaW9uIl1dID0gcmV2KFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChuYW1lID0gIlJkQnUiLCBuID0gOSkpCgojIFNhbXBsZSBhbm5vdGF0aW9uICh0b3AgYW5ub3RhdGlvbikKbGlzdF9jb2xvcnNbWyJzYW1wbGVfdHlwZSJdXSA9IHNhbXBsZV90eXBlX2NvbG9ycwpsaXN0X2NvbG9yc1tbInNhbXBsZV9pZGVudGlmaWVyIl1dID0gc2V0TmFtZXMobm0gPSBzYW1wbGVfaW5mbyRzYW1wbGVfaWRlbnRpZmllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9pbmZvJGNvbG9yKQojIENlbGxzIG9yZGVyCmNvbHVtbl9vcmRlciA9IHN1YnNvYmpAbWV0YS5kYXRhICU+JQogIGRwbHlyOjphcnJhbmdlKHNhbXBsZV90eXBlLCBzYW1wbGVfaWRlbnRpZmllcikgJT4lCiAgcm93bmFtZXMoKQpjb2x1bW5fb3JkZXIgPSBtYXRjaChjb2x1bW5fb3JkZXIsIHJvd25hbWVzKHN1YnNvYmpAbWV0YS5kYXRhKSkKCiMgSGVhdG1hcApoYV90b3AgPSBIZWF0bWFwQW5ub3RhdGlvbihzYW1wbGVfdHlwZSA9IHN1YnNvYmokc2FtcGxlX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9pZGVudGlmaWVyID0gc3Vic29iaiRzYW1wbGVfaWRlbnRpZmllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChzYW1wbGVfdHlwZSA9IGxpc3RfY29sb3JzW1sic2FtcGxlX3R5cGUiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2lkZW50aWZpZXIgPSBsaXN0X2NvbG9yc1tbInNhbXBsZV9pZGVudGlmaWVyIl1dKSkKCiMgSGVhdG1hcApodCA9IEhlYXRtYXAoYXMubWF0cml4KG1hdF9leHByKSwKICAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9ICJFeHByZXNzaW9uIiwgYXQgPSBjKDAsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJsb3ciLCAiaGlnaCIpKSwKICAgICAgICAgICAgIGNvbCA9IGxpc3RfY29sb3JzW1siZXhwcmVzc2lvbiJdXSwKICAgICAgICAgICAgIHRvcF9hbm5vdGF0aW9uID0gaGFfdG9wLAogICAgICAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgIGNvbHVtbl9vcmRlciA9IGNvbHVtbl9vcmRlciwKICAgICAgICAgICAgIGNvbHVtbl9nYXAgPSB1bml0KDIsICJtbSIpLAogICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICByb3dfdGl0bGUgPSBOVUxMLAogICAgICAgICAgICAgcm93X25hbWVzX2dwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE0LCBmb250ZmFjZSA9ICJwbGFpbiIpLAogICAgICAgICAgICAgdXNlX3Jhc3RlciA9IEZBTFNFLAogICAgICAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICBib3JkZXIgPSBUUlVFKQoKQ29tcGxleEhlYXRtYXA6OmRyYXcoaHQsCiAgICAgICAgICAgICAgICAgICAgIG1lcmdlX2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwKICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQpgYGAKCgpEb3RwbG90IG9mIERFIGdlbmVzIGZvciBDRDQgVCBjZWxscyA6CgpgYGB7ciBmaWdfaWNfZG90cGxvdF9jZDQsIGZpZy5oZWlnaHQgPSAzLjUsIGZpZy53aWR0aCA9IDV9CnN1YnNvYmogPSBzdWJzZXQoc29ial9pYywgY2x1c3Rlcl90eXBlID09ICJDRDQgVCBjZWxscyIpCiMgZmVhdHVyZXNfb2kgPSBjKAojICAgIyBIQUxMTUFSS19UTkZBX1NJR05BTElOR19WSUFfTkZLQgojICAgIlJJUEsyIiwgIktMRjkiLCAiUEVSMSIsICJGT1MiLCAiQlRHMSIsICJQVEdFUjQiLCAiQklSQzMiLCAiQVJFRyIsICJLTEY2IiwgIlpGUDM2IiwgIk5GS0JJQSIsCiMgICAjIFJFQUNUT01FX1JIT19HVFBBU0VfRUZGRUNUT1JTCiMgICAiQ1lCQSIsICJBUlBDMyIsICJDRkwxIiwgIlJQUzI3IiwgIkNBTE0xIiwgIkFDVEIiLAojICAgIyBHT0JQX0dSQU5aWU1FX01FRElBVEVEX1BST0dSQU1NRURfQ0VMTF9ERUFUSF9TSUdOQUxJTkdfUEFUSFdBWQojICAgIkJOSVAzIiwgIkdaTUEiLCAiR1pNQiIsICJMQU1QMSIsICJOS0c3IiwgIlNSR04iLCAiVUJFNEIiLAojICAgIyBHT0JQX1BPU0lUSVZFX1JFR1VMQVRJT05fT0ZfTUVNT1JZX1RfQ0VMTF9ESUZGRVJFTlRJQVRJT04KIyAgICJDRDQ2IiwgIkhMQS1EUkEiLCAiSExBLURSQjEiLCAiSUwxMlJCMSIsICJJTDIzQSIsICJJTDIzUiIsICJUTkZTRjQiLAojICAgIktMUkIxIikKZmVhdHVyZXNfb2kgPSBjKCJHWk1BIiwgIktMUkIxIiwgIkJURzEiLCAiWkZQMzYiLCAiTkZLQklBIiwgIlRYTklQIiwgIkNYQ1I0IikKClNldXJhdDo6RG90UGxvdChzdWJzb2JqLAogICAgICAgICAgICAgICAgYXNzYXkgPSAiUk5BIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZmVhdHVyZXNfb2ksCiAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzYW1wbGVfdHlwZSIsCiAgICAgICAgICAgICAgICBzY2FsZSA9IEZBTFNFKSArCiAgZ2dwbG90Mjo6Y29vcmRfZmxpcCgpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzID0gYXF1YXJpdXM6OmNvbG9yX2dlbmUpICsKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpCmBgYAoKSGVhdG1hcCBmb3IgQ0Q0IFQgY2VsbHMgOgoKYGBge3IgZmlnX2ljX2hlYXRtYXBfY2Q0LCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gNCwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CiMgTWF0cml4Cm1hdF9leHByID0gU2V1cmF0OjpHZXRBc3NheURhdGEoc3Vic29iaikKbWF0X2V4cHIgPSBtYXRfZXhwcltmZWF0dXJlc19vaSwgXQptYXRfZXhwciA9IE1hdHJpeDo6dChtYXRfZXhwcikKbWF0X2V4cHIgPSBkeW51dGlsczo6c2NhbGVfcXVhbnRpbGUobWF0X2V4cHIpICMgYmV0d2VlbiAwIGFuZCAxCm1hdF9leHByID0gTWF0cml4Ojp0KG1hdF9leHByKQpkaW0obWF0X2V4cHIpICMgZ2VuZXMgeCBjZWxscwojIyBDb2xvcnMKbGlzdF9jb2xvcnMgPSBsaXN0KCkKCiMgSGVhdG1hcApsaXN0X2NvbG9yc1tbImV4cHJlc3Npb24iXV0gPSByZXYoUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG5hbWUgPSAiUmRCdSIsIG4gPSA5KSkKCiMgU2FtcGxlIGFubm90YXRpb24gKHRvcCBhbm5vdGF0aW9uKQpsaXN0X2NvbG9yc1tbInNhbXBsZV90eXBlIl1dID0gc2FtcGxlX3R5cGVfY29sb3JzCmxpc3RfY29sb3JzW1sic2FtcGxlX2lkZW50aWZpZXIiXV0gPSBzZXROYW1lcyhubSA9IHNhbXBsZV9pbmZvJHNhbXBsZV9pZGVudGlmaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2luZm8kY29sb3IpCiMgQ2VsbHMgb3JkZXIKY29sdW1uX29yZGVyID0gc3Vic29iakBtZXRhLmRhdGEgJT4lCiAgZHBseXI6OmFycmFuZ2Uoc2FtcGxlX3R5cGUsIHNhbXBsZV9pZGVudGlmaWVyKSAlPiUKICByb3duYW1lcygpCmNvbHVtbl9vcmRlciA9IG1hdGNoKGNvbHVtbl9vcmRlciwgcm93bmFtZXMoc3Vic29iakBtZXRhLmRhdGEpKQoKIyBIZWF0bWFwCmhhX3RvcCA9IEhlYXRtYXBBbm5vdGF0aW9uKHNhbXBsZV90eXBlID0gc3Vic29iaiRzYW1wbGVfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2lkZW50aWZpZXIgPSBzdWJzb2JqJHNhbXBsZV9pZGVudGlmaWVyLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBsaXN0KHNhbXBsZV90eXBlID0gbGlzdF9jb2xvcnNbWyJzYW1wbGVfdHlwZSJdXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfaWRlbnRpZmllciA9IGxpc3RfY29sb3JzW1sic2FtcGxlX2lkZW50aWZpZXIiXV0pKQoKIyBIZWF0bWFwCmh0ID0gSGVhdG1hcChhcy5tYXRyaXgobWF0X2V4cHIpLAogICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KHRpdGxlID0gIkV4cHJlc3Npb24iLCBhdCA9IGMoMCwgMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImxvdyIsICJoaWdoIikpLAogICAgICAgICAgICAgY29sID0gbGlzdF9jb2xvcnNbWyJleHByZXNzaW9uIl1dLAogICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBoYV90b3AsCiAgICAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgY29sdW1uX29yZGVyID0gY29sdW1uX29yZGVyLAogICAgICAgICAgICAgY29sdW1uX2dhcCA9IHVuaXQoMiwgIm1tIiksCiAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgIHJvd190aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gMTQsIGZvbnRmYWNlID0gInBsYWluIiksCiAgICAgICAgICAgICB1c2VfcmFzdGVyID0gRkFMU0UsCiAgICAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgIGJvcmRlciA9IFRSVUUpCgpDb21wbGV4SGVhdG1hcDo6ZHJhdyhodCwKICAgICAgICAgICAgICAgICAgICAgbWVyZ2VfbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKCiMgSEZTQwoKIyMgU2V0dGluZ3MKCldlIGxvYWQgdGhlIEhGU0NzIGRhdGFzZXQgOgoKYGBge3Igc29ial9oZnNjfQpzb2JqX2hmc2MgPSByZWFkUkRTKHBhc3RlMChkYXRhX2RpciwgIi80X3pvb20vMl96b29tX2hmc2MvaGZzY19zb2JqLnJkcyIpKQpzb2JqX2hmc2MKYGBgCgoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBuYW1lIHRvIHZpc3VhbGl6ZSBjZWxscyA6CgpgYGB7ciBzb2JqX25hbWUyRF9oZnNjfQpuYW1lMkQgPSAiaGFybW9ueV8yNF90c25lIgpgYGAKClRvIHJlcHJlc2VudCByZXN1bHRzIGZyb20gZGlmZmVyZW50aWFsIGV4cHJlc3Npb24sIHdlIGxvYWQgdGhlIGFuYWx5c2VzIHJlc3VsdHMgOgoKYGBge3IgbGlzdF9yZXN1bHRzX2hmc2N9Cmxpc3RfcmVzdWx0cyA9IHJlYWRSRFMocGFzdGUwKGRhdGFfZGlyLCAiLzRfem9vbS8yX3pvb21faGZzYy9oZnNjX2xpc3RfcmVzdWx0cy5yZHMiKSkKCmxhcHBseShsaXN0X3Jlc3VsdHMsIEZVTiA9IG5hbWVzKQpgYGAKCiMjIEZpZ3VyZXMKCkhGU0NzIG9uIHRoZSBmdWxsIGF0bGFzIDoKCmBgYHtyIGZpZ19oZnNjX2xvY2F0aW9uLCBmaWcud2lkdGggPSAyLCBmaWcuaGVpZ2h0ID0gMn0Kc29iaiRpc19oZnNjID0gKGNvbG5hbWVzKHNvYmopICVpbiUgY29sbmFtZXMoc29ial9oZnNjKSkKClNldXJhdDo6RGltUGxvdChzb2JqLCByZWR1Y3Rpb24gPSBuYW1lMkRfYXRsYXMsIHB0LnNpemUgPSAwLjAwMDAwMSwKICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gImlzX2hmc2MiLCBvcmRlciA9ICJUUlVFIikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGNvbG9yX21hcmtlcnNbWyJIRlNDIl1dLCBiZ19jb2xvciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoVFJVRSwgRkFMU0UpKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJIRlNDcyIsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMChuY29sKHNvYmpfaGZzYyksICIgY2VsbHMiKSkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKS1JUMTUgZXhwcmVzc2lvbiA6CgpgYGB7ciBmaWdfaGZzY19rcnQxNSwgZmlnLndpZHRoID0gMiwgZmlnLmhlaWdodCA9IDJ9ClNldXJhdDo6RmVhdHVyZVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJEX2F0bGFzLCBwdC5zaXplID0gMC4wMDAwMDEsCiAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiS1JUMTUiKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGFxdWFyaXVzOjpjb2xvcl9nZW5lKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKyBTZXVyYXQ6Ok5vTGVnZW5kKCkKYGBgCgpHZW5lcyBvZiBpbnRlcmVzdCA6CgpgYGB7ciBmaWdfaGZzY19nZW5lcywgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDR9CmdlbmVzID0gYygiVEdGQjIiLCAiQU5HUFRMNyIsICJGR0YxOCIsICJNR1AiLCAiRVBDQU0iLCAiS1JUNzUiLCAiTk9UQ0gzIiwgIlBUSExIIikKCnBsb3RfbGlzdCA9IGxhcHBseShjKDE6bGVuZ3RoKGdlbmVzKSksIEZVTiA9IGZ1bmN0aW9uKGdlbmVfaWQpIHsKICBnZW5lID0gZ2VuZXNbW2dlbmVfaWRdXQogIAogIHNvYmpfaGZzYyRteV9nZW5lID0gU2V1cmF0OjpGZXRjaERhdGEoc29ial9oZnNjLCBnZW5lKVssIDFdICU+JQogICAgYXF1YXJpdXM6OnJ1bl9yZXNjYWxlKC4sIG5ld19taW4gPSAwLCBuZXdfbWF4ID0gMTApCiAgCiAgU2V1cmF0OjpGZWF0dXJlUGxvdChzb2JqX2hmc2MsIGZlYXR1cmVzID0gIm15X2dlbmUiLCByZWR1Y3Rpb24gPSBuYW1lMkQpICsKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSBhcXVhcml1czo6Y29sb3JfZ2VuZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAsIGJ5ID0gMi41KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJtaW4iLCByZXAoIiIsIDMpLCAibWF4IikpICsKICAgIGdncGxvdDI6OmxhYnModGl0bGUgPSBnZW5lKSArCiAgICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE3KSwKICAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNSksCiAgICAgICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICBTZXVyYXQ6Ok5vQXhlcygpCn0pCgpwbG90X2xpc3QKYGBgCgpgYGB7ciBmaWdfaGZzY19nZW5lc19zcGxpdCwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDR9CnBsb3RfbGlzdCA9IGxhcHBseShjKCJJRklUTTMiLCAiTUlGIiwgIkRESVQ0IiksIEZVTiA9IGZ1bmN0aW9uKG9uZV9nZW5lKSB7CiAgcCA9IGFxdWFyaXVzOjpwbG90X3NwbGl0X2RpbXJlZChzb2JqX2hmc2MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWR1Y3Rpb24gPSBuYW1lMkQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGxpdF9ieSA9ICJzYW1wbGVfdHlwZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9IG9uZV9nZW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfcGFsZXR0ZSA9IHZpcmlkaXM6OnZpcmlkaXMobiA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1haW5fcHRfc2l6ZSA9IDAuNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJnX3B0X3NpemUgPSAwLjYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZ19jb2xvciA9ICJncmF5OTUiKQogIHAgPSBwYXRjaHdvcms6OndyYXBfcGxvdHMocCwgbnJvdyA9IDEpICsKICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSArCiAgICBnZ3Bsb3QyOjp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSAmCiAgICBnZ3Bsb3QyOjp0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQogIHJldHVybihwKQp9KQoKcGxvdF9saXN0CmBgYAoKUHJvamVjdCBuYW1lIDoKCmBgYHtyIGZpZ19oZnNjX3Byb2plY3RfbmFtZSwgZmlnLndpZHRoID0gNCwgZmlnLmhlaWdodCA9IDR9CiMgUmFuZG9tIG9yZGVyCnNldC5zZWVkKDEyMzQpCnJuZF9vcmRlciA9IHNhbXBsZShjb2xuYW1lcyhzb2JqX2hmc2MpLCByZXBsYWNlID0gRkFMU0UsIHNpemUgPSBuY29sKHNvYmpfaGZzYykpCgojIEV4dHJhY3QgY29vcmRpbmF0ZXMKY2VsbHNfY29vcmQgPSBzb2JqX2hmc2NAcmVkdWN0aW9uc1tbbmFtZTJEXV1AY2VsbC5lbWJlZGRpbmdzICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICBgY29sbmFtZXM8LWAoYygiRGltMSIsICJEaW0yIikpCmNlbGxzX2Nvb3JkJHByb2plY3RfbmFtZSA9IHNvYmpfaGZzYyRwcm9qZWN0X25hbWUKY2VsbHNfY29vcmQgPSBjZWxsc19jb29yZFsocm5kX29yZGVyKSwgXQoKIyBQbG90CmdncGxvdDI6OmdncGxvdChjZWxsc19jb29yZCwgYWVzKHggPSBEaW0xLCB5ID0gRGltMiwgY29sID0gcHJvamVjdF9uYW1lKSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoc2l6ZSA9IDEuMikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKSArCiAgZ2dwbG90Mjo6dGhlbWVfdm9pZCgpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpDbHVzdGVyIDoKCmBgYHtyIGZpZ19oZnNjX2NsdXN0ZXJzLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0KU2V1cmF0OjpEaW1QbG90KHNvYmpfaGZzYywgcmVkdWN0aW9uID0gbmFtZTJELCBwdC5zaXplID0gMSwKICAgICAgICAgICAgICAgIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gVFJVRSkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpICsKICBTZXVyYXQ6Ok5vQXhlcygpICsKICBTZXVyYXQ6Ok5vTGVnZW5kKCkKYGBgCgpIZWF0bWFwIHdpdGggcHJvcG9ydGlvbnMgOgoKYGBge3IgZmlnX2hmc2NfaGVhdG1hcCwgZmlnLndpZHRoID0gNC41LCBmaWcuaGVpZ2h0ID0gNywgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmNsdXN0ZXJfbWFya2VycyA9IGMoIlRHRkIyIiwgIkFOR1BUTDciLCAiRVBDQU0iLCAiS1JUNzUiLCAiTk9UQ0gzIiwgIlBUSExIIiwKICAgICAgICAgICAgICAgICAgICAicGVyY2VudC5tdCIsICJsb2dfbkNvdW50X1JOQSIpCgojIyBCb3R0b20gYW5ub3RhdGlvbiA6IGdlbmUgZXhwcmVzc2lvbiBieSBjbHVzdGVyCmh0X2Fubm90ID0gU2V1cmF0OjpGZXRjaERhdGEoc29ial9oZnNjLCBzbG90ID0gImRhdGEiLCB2YXJzID0gY2x1c3Rlcl9tYXJrZXJzKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkKaHRfYW5ub3QkY2x1c3RlcnMgPSBzb2JqX2hmc2Mkc2V1cmF0X2NsdXN0ZXJzCmh0X2Fubm90ID0gaHRfYW5ub3QgJT4lCiAgZHBseXI6Omdyb3VwX2J5KGNsdXN0ZXJzKSAlPiUKICBkcGx5cjo6c3VtbWFyaXNlX2FsbChmdW5zKCdtZWFuJyA9IG1lYW4pKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgZHBseXI6OnNlbGVjdCgtY2x1c3RlcnMpICU+JQogIGBjb2xuYW1lczwtYChjKGNsdXN0ZXJfbWFya2VycykpCgpoYV9ib3R0b20gPSBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcEFubm90YXRpb24oZGYgPSBodF9hbm5vdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoID0gImNvbHVtbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBzZXROYW1lcyhubSA9IGNsdXN0ZXJfbWFya2VycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcHBseShjbHVzdGVyX21hcmtlcnMsIEZVTiA9IGNvbG9yX2Z1bikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9uYW1lX3NpZGUgPSAibGVmdCIpCgojIyBSaWdodCBhbm5vdGF0aW9uIDogbnVtYmVyIG9mIGNlbGxzIGJ5IGRhdGFzZXQKaHRfYW5ub3QgPSB0YWJsZShzb2JqX2hmc2Mkc2FtcGxlX2lkZW50aWZpZXIpICU+JQogIGFzLmRhdGEuZnJhbWUudGFibGUoKSAlPiUKICBgY29sbmFtZXM8LWAoYygic2FtcGxlX2lkZW50aWZpZXIiLCAibmJfY2VsbHMiKSkgJT4lCiAgYHJvd25hbWVzPC1gKC4kc2FtcGxlX2lkZW50aWZpZXIpICU+JQogIGRwbHlyOjpzZWxlY3QoLXNhbXBsZV9pZGVudGlmaWVyKQoKaGFfcmlnaHQgPSBDb21wbGV4SGVhdG1hcDo6SGVhdG1hcEFubm90YXRpb24oCiAgZGYgPSBodF9hbm5vdCwKICB3aGljaCA9ICJyb3ciLAogIHNob3dfbGVnZW5kID0gVFJVRSwKICBhbm5vdGF0aW9uX25hbWVfc2lkZSA9ICJib3R0b20iLAogIGNvbCA9IGxpc3QobmJfY2VsbHMgID0gY2lyY2xpemU6OmNvbG9yUmFtcDIoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKG5hbWUgPSAiR3JleXMiLCBuID0gOSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZnJvbSA9IHJhbmdlKGh0X2Fubm90JG5iX2NlbGxzKVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IHJhbmdlKGh0X2Fubm90JG5iX2NlbGxzKVsyXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gOSkpKSkKCiMjIEhlYXRtYXAKaHQgPSBhcXVhcml1czo6cGxvdF9wcm9wX2hlYXRtYXAoZGYgPSBzb2JqX2hmc2NAbWV0YS5kYXRhWywgYygic2FtcGxlX2lkZW50aWZpZXIiLCAic2V1cmF0X2NsdXN0ZXJzIildLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3R0b21fYW5ub3RhdGlvbiA9IGhhX2JvdHRvbSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHRfYW5ub3RhdGlvbiA9IGhhX3JpZ2h0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fbmFtZXNfY2VudGVyZWQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9wX21hcmdpbiA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIobmFtZXMgPSBzYW1wbGVfaW5mbyRzYW1wbGVfaWRlbnRpZmllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvd190aXRsZSA9ICJTYW1wbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW5fdGl0bGUgPSAiQ2x1c3RlciIpCgpDb21wbGV4SGVhdG1hcDo6ZHJhdyhodCwKICAgICAgICAgICAgICAgICAgICAgbWVyZ2VfbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQpgYGAKCkRvdHBsb3Qgb2YgREUgZ2VuZXMgaW4gY2x1c3RlcnMgMCBhbmQgOCwgYmV0d2VlbiBIUyBhbmQgSEQgOgoKYGBge3IgZmlnX2hmc2NfZG90cGxvdCwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDV9CiMgZmVhdHVyZXNfb2kgPSByb3duYW1lcyhsaXN0X3Jlc3VsdHMkY2x1c3Rlcl8wXzgpCiMgZmVhdHVyZXNfb2kgPSBmZWF0dXJlc19vaVshZ3JlcGwoZmVhdHVyZXNfb2ksIHBhdHRlcm4gPSAiXlJQIildCgpzdWJzb2JqID0gc3Vic2V0KHNvYmpfaGZzYywgc2V1cmF0X2NsdXN0ZXJzICVpbiUgYygwLDgpKQoKZmVhdHVyZXNfb2kgPSBjKCJITEEtQyIsICJITEEtQiIsICJJRklUTTMiLCAiTUlGIiwgIkpVTkIiLCAiTUFSQ0tTTDEiLAogICAgICAgICAgICAgICAgIkxUQlAyIiwgIlBESzQiLCAiRERJVDQiLCAiUzEwMEExMSIpCgpTZXVyYXQ6OkRvdFBsb3Qoc3Vic29iaiwKICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIsCiAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGZlYXR1cmVzX29pLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgc2NhbGUgPSBGQUxTRSkgKwogIGdncGxvdDI6OmNvb3JkX2ZsaXAoKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGFxdWFyaXVzOjpjb2xvcl9nZW5lKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQpgYGAKCkhlYXRtYXAgZm9yIGNsdWxzdGVyIDAgYW5kIDggOgoKYGBge3IgZmlnX2hmc2NfaGVhdG1hcF9jbHVzdGVyMDgsIGZpZy53aWR0aCA9IDUsIGZpZy5oZWlnaHQgPSA1LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyBNYXRyaXgKbWF0X2V4cHIgPSBTZXVyYXQ6OkdldEFzc2F5RGF0YShzdWJzb2JqKQptYXRfZXhwciA9IG1hdF9leHByW2ZlYXR1cmVzX29pLCBdCm1hdF9leHByID0gTWF0cml4Ojp0KG1hdF9leHByKQptYXRfZXhwciA9IGR5bnV0aWxzOjpzY2FsZV9xdWFudGlsZShtYXRfZXhwcikgIyBiZXR3ZWVuIDAgYW5kIDEKbWF0X2V4cHIgPSBNYXRyaXg6OnQobWF0X2V4cHIpCmRpbShtYXRfZXhwcikgIyBnZW5lcyB4IGNlbGxzCiMjIENvbG9ycwpsaXN0X2NvbG9ycyA9IGxpc3QoKQoKIyBIZWF0bWFwCmxpc3RfY29sb3JzW1siZXhwcmVzc2lvbiJdXSA9IHJldihSQ29sb3JCcmV3ZXI6OmJyZXdlci5wYWwobmFtZSA9ICJSZEJ1IiwgbiA9IDkpKQoKIyBTYW1wbGUgYW5ub3RhdGlvbiAodG9wIGFubm90YXRpb24pCmxpc3RfY29sb3JzW1sic2FtcGxlX3R5cGUiXV0gPSBzYW1wbGVfdHlwZV9jb2xvcnMKbGlzdF9jb2xvcnNbWyJzYW1wbGVfaWRlbnRpZmllciJdXSA9IHNldE5hbWVzKG5tID0gc2FtcGxlX2luZm8kc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfaW5mbyRjb2xvcikKIyBsaXN0X2NvbG9yc1tbInNldXJhdF9jbHVzdGVycyJdXSA9IHNldE5hbWVzKGFxdWFyaXVzOjpnZ19jb2xvcl9odWUobGVuZ3RoKGxldmVscyhzdWJzb2JqJHNldXJhdF9jbHVzdGVycykpKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5tID0gbGV2ZWxzKHN1YnNvYmokc2V1cmF0X2NsdXN0ZXJzKSkKIyBDZWxscyBvcmRlcgpjb2x1bW5fb3JkZXIgPSBzdWJzb2JqQG1ldGEuZGF0YSAlPiUKICBkcGx5cjo6YXJyYW5nZShzYW1wbGVfdHlwZSwgc2FtcGxlX2lkZW50aWZpZXIpICU+JQogIHJvd25hbWVzKCkKY29sdW1uX29yZGVyID0gbWF0Y2goY29sdW1uX29yZGVyLCByb3duYW1lcyhzdWJzb2JqQG1ldGEuZGF0YSkpCgojIEhlYXRtYXAKaGFfdG9wID0gSGVhdG1hcEFubm90YXRpb24oc2FtcGxlX3R5cGUgPSBzdWJzb2JqJHNhbXBsZV90eXBlLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfaWRlbnRpZmllciA9IHN1YnNvYmokc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY2x1c3RlcnMgPSBzdWJzb2JqJHNldXJhdF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChzYW1wbGVfdHlwZSA9IGxpc3RfY29sb3JzW1sic2FtcGxlX3R5cGUiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2lkZW50aWZpZXIgPSBsaXN0X2NvbG9yc1tbInNhbXBsZV9pZGVudGlmaWVyIl1dCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBjbHVzdGVycyA9IGxpc3RfY29sb3JzW1sic2V1cmF0X2NsdXN0ZXJzIl1dCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCgojIEhlYXRtYXAKaHQgPSBIZWF0bWFwKGFzLm1hdHJpeChtYXRfZXhwciksCiAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QodGl0bGUgPSAiRXhwcmVzc2lvbiIsIGF0ID0gYygwLCAxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygibG93IiwgImhpZ2giKSksCiAgICAgICAgICAgICBjb2wgPSBsaXN0X2NvbG9yc1tbImV4cHJlc3Npb24iXV0sCiAgICAgICAgICAgICB0b3BfYW5ub3RhdGlvbiA9IGhhX3RvcCwKICAgICAgICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICBjb2x1bW5fb3JkZXIgPSBjb2x1bW5fb3JkZXIsCiAgICAgICAgICAgICBjb2x1bW5fZ2FwID0gdW5pdCgyLCAibW0iKSwKICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgcm93X3RpdGxlID0gTlVMTCwKICAgICAgICAgICAgIHJvd19uYW1lc19ncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxNCwgZm9udGZhY2UgPSAicGxhaW4iKSwKICAgICAgICAgICAgIHVzZV9yYXN0ZXIgPSBGQUxTRSwKICAgICAgICAgICAgIHNob3dfaGVhdG1hcF9sZWdlbmQgPSBUUlVFLAogICAgICAgICAgICAgYm9yZGVyID0gVFJVRSkKCkNvbXBsZXhIZWF0bWFwOjpkcmF3KGh0LAogICAgICAgICAgICAgICAgICAgICBtZXJnZV9sZWdlbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIsCiAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAiYm90dG9tIikKYGBgCgpWaW9saW4gcGxvdCBvZiBJRklUTTMgOgoKYGBge3IgZmlnX2hmc2NfaWZpdG0zLCBmaWcud2lkdGggPSAzLCBmaWcuaGVpZ2h0ID0gNH0KdGFibGUoc3Vic29iaiRzYW1wbGVfdHlwZSkKCmlmaXRtM19ocyA9IHN1YnNvYmpAYXNzYXlzJFJOQUBkYXRhWyJJRklUTTMiLCBzdWJzb2JqJHNhbXBsZV90eXBlID09ICJIUyJdCmlmaXRtM19oZCA9IHN1YnNvYmpAYXNzYXlzJFJOQUBkYXRhWyJJRklUTTMiLCBzdWJzb2JqJHNhbXBsZV90eXBlID09ICJIRCJdCmlmaXRtM19oc19WU19pZml0bTNfaGQgPSBzdGF0czo6dC50ZXN0KGlmaXRtM19ocywgaWZpdG0zX2hkKQppZml0bTNfaHNfVlNfaWZpdG0zX2hkCgpTZXVyYXQ6OlZsblBsb3Qoc3Vic29iaiwgZ3JvdXAuYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiSUZJVE0zIiwgY29scyA9IHNhbXBsZV90eXBlX2NvbG9ycykgKwogIGdncGxvdDI6OnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKVmlvbGluIHBsb3Qgb2YgUERLNCA6CgpgYGB7ciBmaWdfaGZzY19wZGs0LCBmaWcud2lkdGggPSAzLCBmaWcuaGVpZ2h0ID0gNH0KdGFibGUoc3Vic29iaiRzYW1wbGVfdHlwZSkKCnBkazRfaHMgPSBzdWJzb2JqQGFzc2F5cyRSTkFAZGF0YVsiUERLNCIsIHN1YnNvYmokc2FtcGxlX3R5cGUgPT0gIkhTIl0KcGRrNF9oZCA9IHN1YnNvYmpAYXNzYXlzJFJOQUBkYXRhWyJQREs0Iiwgc3Vic29iaiRzYW1wbGVfdHlwZSA9PSAiSEQiXQpwZGs0X2hzX1ZTX3BkazRfaGQgPSBzdGF0czo6dC50ZXN0KHBkazRfaHMsIHBkazRfaGQpCnBkazRfaHNfVlNfcGRrNF9oZAoKU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gIlBESzQiLCBjb2xzID0gc2FtcGxlX3R5cGVfY29sb3JzKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIElCTCBhbmQgT1JTCgojIyBTZXR0aW5ncwoKV2UgbG9hZCB0aGUgSUJMICsgT1JTIGRhdGFzZXQgOgoKYGBge3Igc29ial9pYmxvcnN9CnNvYmpfaWJsb3JzID0gcmVhZFJEUyhwYXN0ZTAoZGF0YV9kaXIsICIvNF96b29tLzNfem9vbV9pYmxtb3JzL2libG1vcnNfc29iai5yZHMiKSkKc29ial9pYmxvcnMKYGBgCgoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBuYW1lIHRvIHZpc3VhbGl6ZSBjZWxscyA6CgpgYGB7ciBzb2JqX25hbWUyRF9pYmxvcnN9Cm5hbWUyRCA9ICJoYXJtb255XzIwX3RzbmUiCmBgYAoKVG8gcmVwcmVzZW50IHJlc3VsdHMgZnJvbSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiwgd2UgbG9hZCB0aGUgYW5hbHlzZXMgcmVzdWx0cyA6CgpgYGB7ciBsaXN0X3Jlc3VsdHNfaWJsb3JzfQpsaXN0X3Jlc3VsdHMgPSByZWFkUkRTKHBhc3RlMChkYXRhX2RpciwgIi80X3pvb20vM196b29tX2libG1vcnMvaWJsbW9yc19saXN0X3Jlc3VsdHMucmRzIikpCgpsYXBwbHkobGlzdF9yZXN1bHRzLCBGVU4gPSBuYW1lcykKYGBgCgojIyBQcmVwYXJhdGlvbgoKV2UgZGVmaW5lZCBjbHVzdGVyIHR5cGUgOgoKYGBge3IgY2x1c3Rlcl90eXBlX2libG9ycywgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDV9CmNsdXN0ZXJfdHlwZSA9IHRhYmxlKHNvYmpfaWJsb3JzJGNlbGxfdHlwZSwgc29ial9pYmxvcnMkc2V1cmF0X2NsdXN0ZXJzKSAlPiUKICBwcm9wLnRhYmxlKC4sIG1hcmdpbiA9IDIpICU+JQogIGFwcGx5KC4sIDIsIHdoaWNoLm1heCkKY2x1c3Rlcl90eXBlID0gc2V0TmFtZXMobm0gPSBuYW1lcyhjbHVzdGVyX3R5cGUpLAogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMoc29ial9pYmxvcnMkY2VsbF90eXBlKVtjbHVzdGVyX3R5cGVdKQoKc29ial9pYmxvcnMkY2x1c3Rlcl90eXBlID0gY2x1c3Rlcl90eXBlW3NvYmpfaWJsb3JzJHNldXJhdF9jbHVzdGVyc10Kc29ial9pYmxvcnMkY2x1c3Rlcl90eXBlID0gZmFjdG9yKHNvYmpfaWJsb3JzJGNsdXN0ZXJfdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxldmVscyhzb2JqX2libG9ycyRjZWxsX3R5cGUpKQpgYGAKCiMjIEZpZ3VyZXMKCklCTCArIE9SUyBvbiB0aGUgZnVsbCBhdGxhcyA6CgpgYGB7ciBmaWdfaWJsb3JzX2xvY2F0aW9uLCBmaWcud2lkdGggPSAyLCBmaWcuaGVpZ2h0ID0gMn0Kc29iaiRjZWxsX2JjID0gY29sbmFtZXMoc29iaikKc29ial9pYmxvcnMkY2VsbF9iYyA9IGNvbG5hbWVzKHNvYmpfaWJsb3JzKQpzb2JqJGlzX2libG9ycyA9IGRwbHlyOjpsZWZ0X2pvaW4oc29iakBtZXRhLmRhdGFbLCBjKCJjZWxsX2JjIiwgInBlcmNlbnQubXQiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb2JqX2libG9yc0BtZXRhLmRhdGFbLCBjKCJjZWxsX2JjIiwgImNsdXN0ZXJfdHlwZSIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gImNlbGxfYmMiKVssICJjbHVzdGVyX3R5cGUiXQoKU2V1cmF0OjpEaW1QbG90KHNvYmosIHJlZHVjdGlvbiA9IG5hbWUyRF9hdGxhcywgcHQuc2l6ZSA9IDAuMDAwMDAxLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiaXNfaWJsb3JzIiwgb3JkZXIgPSAiVFJVRSIpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhjb2xvcl9tYXJrZXJzW2MoIklCTCIsICJPUlMiKV0sIGJnX2NvbG9yKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygiSUJMIiwgIk9SUyIsIE5BKSwgbmEudmFsdWUgPSBiZ19jb2xvcikgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiSUJMICsgT1JTIiwKICAgICAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKG5jb2woc29ial9pYmxvcnMpLCAiIGNlbGxzIikpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCgpQcm9qZWN0IG5hbWUgOgoKYGBge3IgZmlnX2libG9yc19wcm9qZWN0X25hbWUsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQojIFJhbmRvbSBvcmRlcgpzZXQuc2VlZCgxMjM0KQpybmRfb3JkZXIgPSBzYW1wbGUoY29sbmFtZXMoc29ial9pYmxvcnMpLCByZXBsYWNlID0gRkFMU0UsIHNpemUgPSBuY29sKHNvYmpfaWJsb3JzKSkKCiMgRXh0cmFjdCBjb29yZGluYXRlcwpjZWxsc19jb29yZCA9IHNvYmpfaWJsb3JzQHJlZHVjdGlvbnNbW25hbWUyRF1dQGNlbGwuZW1iZWRkaW5ncyAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgYGNvbG5hbWVzPC1gKGMoIkRpbTEiLCAiRGltMiIpKQpjZWxsc19jb29yZCRwcm9qZWN0X25hbWUgPSBzb2JqX2libG9ycyRwcm9qZWN0X25hbWUKY2VsbHNfY29vcmQgPSBjZWxsc19jb29yZFsocm5kX29yZGVyKSwgXQoKIyBQbG90CmdncGxvdDI6OmdncGxvdChjZWxsc19jb29yZCwgYWVzKHggPSBEaW0xLCB5ID0gRGltMiwgY29sID0gcHJvamVjdF9uYW1lKSkgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoc2l6ZSA9IDEuMikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBzYW1wbGVfaW5mbyRjb2xvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2FtcGxlX2luZm8kcHJvamVjdF9uYW1lKSArCiAgZ2dwbG90Mjo6dGhlbWVfdm9pZCgpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpDbHVzdGVyIDoKCmBgYHtyIGZpZ19pYmxvcnNfY2x1c3RlcnMsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQpTZXVyYXQ6OkRpbVBsb3Qoc29ial9pYmxvcnMsIHJlZHVjdGlvbiA9IG5hbWUyRCwgcHQuc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBsYWJlbCA9IFRSVUUpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKQ2x1c3RlciB0eXBlIDoKCmBgYHtyIGZpZ19pYmxvcnNfY2x1c3Rlcl90eXBlLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0KU2V1cmF0OjpEaW1QbG90KHNvYmpfaWJsb3JzLCByZWR1Y3Rpb24gPSBuYW1lMkQsIHB0LnNpemUgPSAxLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2x1c3Rlcl90eXBlIiwgY29scyA9IGNvbG9yX21hcmtlcnMpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKQ2x1c3RlciB0eXBlIHNwbGl0IGJ5IHNhbXBsZSB0eXBlIDoKCmBgYHtyIGZpZ19pYmxvcnNfY2x1c3Rlcl90eXBlX3NwbGl0LCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNH0KcGxvdF9saXN0ID0gYXF1YXJpdXM6OnBsb3Rfc3BsaXRfZGltcmVkKHNvYmpfaWJsb3JzLCByZWR1Y3Rpb24gPSBuYW1lMkQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieSA9ICJjbHVzdGVyX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfY29sb3IgPSBjb2xvcl9tYXJrZXJzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BsaXRfYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmdfcHRfc2l6ZSA9IDEsIG1haW5fcHRfc2l6ZSA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZ19jb2xvciA9IGJnX2NvbG9yKQoKcGF0Y2h3b3JrOjp3cmFwX3Bsb3RzKHBsb3RfbGlzdCkgJgogIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCkRFIGdlbmVzIGJldHdlZW4gSUJMIGFuZCBPUlMgOgoKYGBge3IgZmlnX2libG9yc19kZV9wb3AsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA2fQptYXJrID0gbGlzdF9yZXN1bHRzJElCTF92c19PUlMkbWFyawptYXJrJGdlbmVfbmFtZSA9IHJvd25hbWVzKG1hcmspCm1hcmtfbGFiZWwgPSByYmluZCgKICAjIHVwLXJlZ3VsYXRlZCBpbiBJQkwKICBtYXJrICU+JSBkcGx5cjo6dG9wX24oLiwgbiA9IDIwLCB3dCA9IGF2Z19sb2dGQyksCiAgIyB1cC1yZWd1bGF0ZWQgaW4gT1JTCiAgbWFyayAlPiUgZHBseXI6OnRvcF9uKC4sIG4gPSAyMCwgd3QgPSAtYXZnX2xvZ0ZDKSwKICAjIHJlcHJlc2VudGF0aXZlIGFuZCBzZWxlY3RpdmUgZm9yIElCTAogIG1hcmsgJT4lIGRwbHlyOjp0b3BfbiguLCBuID0gMjAsIHd0ID0gKHBjdC4xIC0gcGN0LjIpKSwKICAjIHJlcHJlc2VudGF0aXZlIGFuZCBzZWxlY3RpdmUgZm9yIE9SUwogIG1hcmsgJT4lIGRwbHlyOjp0b3BfbiguLCBuID0gMjAsIHd0ID0gLShwY3QuMSAtIHBjdC4yKSkpICU+JQogIGRwbHlyOjpkaXN0aW5jdCgpCm1hcmtfbGFiZWwgPSBtYXJrX2xhYmVsWyFncmVwbChyb3duYW1lcyhtYXJrX2xhYmVsKSwgcGF0dGVybiA9ICJeTVQiKSwgXQoKZ2dwbG90Mjo6Z2dwbG90KG1hcmssIGFlcyh4ID0gcGN0LjEsIHkgPSBwY3QuMiwgY29sID0gYXZnX2xvZ0ZDKSkgKwogIGdncGxvdDI6Omdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbHR5ID0gMikgKwogIGdncGxvdDI6Omdlb21fcG9pbnQoKSArCiAgZ2dyZXBlbDo6Z2VvbV9sYWJlbF9yZXBlbChkYXRhID0gbWFya19sYWJlbCwgbWF4Lm92ZXJsYXBzID0gSW5mLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHggPSBwY3QuMSwgeSA9IHBjdC4yLCBsYWJlbCA9IGdlbmVfbmFtZSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSAiYmxhY2siLCBmaWxsID0gTkEsIHNpemUgPSAzLCBsYWJlbC5zaXplID0gTkEpICsKICBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gIkRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyIsCiAgICAgICAgICAgICAgICBzdWJ0aXRsZSA9ICJiZXR3ZWVuIElCTCBhbmQgT1JTIikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSBhcXVhcml1czo6Y29sb3JfY252WzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSBhcXVhcml1czo6Y29sb3JfY252WzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gYXF1YXJpdXM6OmNvbG9yX2NudlszXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwKSArCiAgZ2dwbG90Mjo6dGhlbWVfY2xhc3NpYygpICsKICBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwKICAgICAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKYGBgCgpHU0VBIGZvciBhbGwgZ2VuZXMsIGluIElCTCwgYmV0d2VlbiBIUyBhbmQgSEQgOgoKYGBge3IgZ3NlYV9pYmwsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNDAsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIGdzX29pID0gYygiUkVBQ1RPTUVfRVhQT1JUX09GX1ZJUkFMX1JJQk9OVUNMRU9QUk9URUlOU19GUk9NX05VQ0xFVVMiLAojICAgICAgICAgICAiR09CUF9SRVNQT05TRV9UT19VVl9DIiwKIyAgICAgICAgICAgIkdPQlBfUE9TSVRJVkVfUkVHVUxBVElPTl9PRl9ISVNUT05FX0gzX0s5X01FVEhZTEFUSU9OIiwKIyAgICAgICAgICAgIkdPQlBfSElTVE9ORV9IM19LMTRfQUNFVFlMQVRJT04iLAojICAgICAgICAgICAiR09CUF9NSVRPUEhBR1kiKQoKbGlzdF9yZXN1bHRzJElCTF9IU192c19IRCRnc2VhQHJlc3VsdCAlPiUKICAjIGRwbHlyOjpmaWx0ZXIoSUQgJWluJSBnc19vaSkgJT4lCiAgZHBseXI6OmZpbHRlcihwdmFsdWUgPCAgMC4wNSkgJT4lCiAgZHBseXI6OnRvcF9uKC4sIG4gPSAyMDAsIHd0ID0gYWJzKE5FUykpICU+JQogIGRwbHlyOjptdXRhdGUodG9vX2xvbmcgPSBpZmVsc2UobmNoYXIoSUQpID4gNjAsIHllcyA9IFRSVUUsIG5vID0gRkFMU0UpKSAlPiUKICBkcGx5cjo6bXV0YXRlKElEID0gc3RyaW5ncjo6c3RyX3N1YihJRCwgZW5kID0gNjApKSAlPiUKICBkcGx5cjo6bXV0YXRlKElEID0gaWZlbHNlKHRvb19sb25nLCB5ZXMgPSBwYXN0ZTAoSUQsICIuLi4iKSwgbm8gPSBJRCkpICU+JQogIGFxdWFyaXVzOjpnc2VhX3Bsb3Qoc2hvd19sZWdlbmQgPSBUUlVFKSArCiAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9ICJHU0VBIHVzaW5nIGFsbCBnZW5lcyAoY291bnQgbWF0cml4KSIpICsKICBnZ3Bsb3QyOjp0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpCmBgYAoKCkdTRUEgZm9yIGFsbCBnZW5lcywgaW4gT1JTLCBiZXR3ZWVuIEhTIGFuZCBIRCA6CgpgYGB7ciBnc2VhX29ycywgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA0MCwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9Cmxpc3RfcmVzdWx0cyRPUlNfSFNfdnNfSEQkZ3NlYUByZXN1bHQgJT4lCiAgIyBkcGx5cjo6ZmlsdGVyKElEICVpbiUgZ3Nfb2kpICU+JQogIGRwbHlyOjpmaWx0ZXIocHZhbHVlIDwgIDAuMDUpICU+JQogIGRwbHlyOjp0b3BfbiguLCBuID0gMjAwLCB3dCA9IGFicyhORVMpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHRvb19sb25nID0gaWZlbHNlKG5jaGFyKElEKSA+IDcwLCB5ZXMgPSBUUlVFLCBubyA9IEZBTFNFKSkgJT4lCiAgZHBseXI6Om11dGF0ZShJRCA9IHN0cmluZ3I6OnN0cl9zdWIoSUQsIGVuZCA9IDcwKSkgJT4lCiAgZHBseXI6Om11dGF0ZShJRCA9IGlmZWxzZSh0b29fbG9uZywgeWVzID0gcGFzdGUwKElELCAiLi4uIiksIG5vID0gSUQpKSAlPiUKICBhcXVhcml1czo6Z3NlYV9wbG90KHNob3dfbGVnZW5kID0gVFJVRSkgKwogIGdncGxvdDI6OmxhYnModGl0bGUgPSAiR1NFQSB1c2luZyBhbGwgZ2VuZXMgKGNvdW50IG1hdHJpeCkiKSArCiAgZ2dwbG90Mjo6dGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApKQpgYGAKClZpb2xpbiBwbG90IGZvciBJQkwgOgoKYGBge3IgZmlnX2libG9yc19pYmwsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gOH0Kc3Vic29iaiA9IHN1YnNldChzb2JqX2libG9ycywgY2x1c3Rlcl90eXBlID09ICJJQkwiKQoKU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiRFVTUDEiLCAiRERJVDQiLCAiTUlGIiwgIkxHQUxTNyIsICJBUkY1IiwgIlMxMDBBOSIpLAogICAgICAgICAgICAgICAgY29scyA9IHNhbXBsZV90eXBlX2NvbG9ycywgbmNvbCA9IDMpICYKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKClZpb2xpbiBwbG90IGZvciBPUlMgOgoKYGBge3IgZmlnX2libG9yc19vcnMsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOH0Kc3Vic29iaiA9IHN1YnNldChzb2JqX2libG9ycywgY2x1c3Rlcl90eXBlID09ICJPUlMiKQoKU2V1cmF0OjpWbG5QbG90KHN1YnNvYmosIGdyb3VwLmJ5ID0gInNhbXBsZV90eXBlIiwKICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiRFVTUDEiLCAiQ0xETjEiLCAiS0xGNiIsICJDVEdGIiwgIkNDTDIiLCAiUzEwMEE5IiwgIklGSTI3IiwgIklGSVRNMyIpLAogICAgICAgICAgICAgICAgY29scyA9IHNhbXBsZV90eXBlX2NvbG9ycywgbmNvbCA9IDQpICYKICBnZ3Bsb3QyOjp0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKClNwbGl0IGJ5IHNhbXBsZSA6CgpgYGB7ciBmaWdfaWJsb3JzX29yc19zcGxpdCwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDR9ClNldXJhdDo6VmxuUGxvdChzdWJzb2JqLCBncm91cC5ieSA9ICJzYW1wbGVfaWRlbnRpZmllciIsCiAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJJRkkyNyIsIGNvbHMgPSBzYW1wbGVfaW5mbyRjb2xvcikgKwogIGdncGxvdDI6OnRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKCgoKRG90cGxvdCBvZiBERSBnZW5lcyBpbiBPUlMsIGJldHdlZW4gY2x1c3RlciA1IGFuZCBvdGhlciBPUlMgOgoKYGBge3IgZmlnX2libG9yc19kb3RwbG90X2NsdXN0ZXI1LCBmaWcuaGVpZ2h0ID0gMjAsIGZpZy53aWR0aCA9IDUsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpzdWJzb2JqID0gc3Vic2V0KHNvYmpfaWJsb3JzLCBjbHVzdGVyX3R5cGUgPT0gIk9SUyIpCnN1YnNvYmogPSBzdWJzZXQoc3Vic29iaiwgc2V1cmF0X2NsdXN0ZXJzICE9IDcpCgojIGZlYXR1cmVzX29pID0gbGlzdF9yZXN1bHRzJGNsdXN0ZXI1X3ZzX09SUyRtYXJrICU+JQojICAgZHBseXI6OmZpbHRlcihwX3ZhbF9hZGogPCAwLjA1KSAlPiUKIyAgIGRwbHlyOjpmaWx0ZXIoYWJzKGF2Z19sb2dGQykgPiAwLjUpICU+JQojICAgZHBseXI6OmFycmFuZ2UoYXZnX2xvZ0ZDKSAlPiUKIyAgIHJvd25hbWVzKCkKCiMgZmVhdHVyZXNfb2kgPSBjKCJZQlgzIiwgIlRYTklQIiwgIktSVDE1IiwgIk5FQVQxIiwgIkNPTDE3QTEiLCAiRlhZRDMiLCAiS1JUMTQiLAojICAgICAgICAgICAgICAgICAiQ1hDTDE0IiwgIk1UMkEiLCAiTVQxRSIsICJGT1MiLCAiSlVOQiIsICJBUVAzIiwgIkdMVUwiLCAiS0xGNSIsCiMgICAgICAgICAgICAgICAgICJHU1RNMyIsICJBTERIM0ExIiwgIkhMQS1DIiwgIkxHQUxTN0IiLCAiU0xDMzhBMiIsICJFSEYiLCAiS0xGMyIsCiMgICAgICAgICAgICAgICAgICJJTDE4IiwgIkNMRUMyQiIsICJJTDIwUkIiLCAiR1BTTTIiLCAiREFBTTEiLCAiRFVTUDEiLCAiS0xGNiIsCiMgICAgICAgICAgICAgICAgICJaRlAzNiIsICJBVEYzIiwgIlJIT0IiLCAiTVQxWCIsICJLTEY0IiwgIkVUUzIiLCAiTkZLQklaIiwgIklEMSIsCiMgICAgICAgICAgICAgICAgICJSTkFTRVQyIiwgIkhPUFgiLCAiV05UNCIsICJQT1UzRjEiLCAiU1BSWTEiLCAiQVIiLCAiVEhTRDQiLCAiUERHRkMiLAojICAgICAgICAgICAgICAgICAiS1JUMzEiLCAiV0ZEQzIiLCAiU1BJTks1IiwgIlNMUEkiLCAiSUwxUjIiLCAiUExBVCIsICJUU0MyMkQzIiwKIyAgICAgICAgICAgICAgICAgIktMRjkiLCAiV05UMyIsICJGR0ZSMyIsICJMQU1CNCIsICJJRkkyNyIsICJEQ04iLCAiTFk2RCIsICJJR0ZCUDMiLCAiV0ZEQzUiLAojICAgICAgICAgICAgICAgICAKIyAgICAgICAgICAgICAgICAgIlMxMDBBMTQiLCAiVE1TQjEwIiwgIkFDVEcxIiwgIkFDVEIiLCAiQ1NUQiIsICJBUE9FIiwgIkNBTEQxIiwgIlNPWDQiLAojICAgICAgICAgICAgICAgICAiU1RNTjEiLCAiTE1PNCIsICJDRUJQQiIsICJUTUVNNDVBIiwgIkNUU0IiLCAiR1BYMiIsICJDMVFUTkYxMiIsICJHSkI2IiwKIyAgICAgICAgICAgICAgICAgIlJCUDEiLCAiVFBNMSIsICJLUlQxNyIsICJDQUxNTDMiLCAiUFROIiwgIkRBUEsyIiwKIyAgICAgICAgICAgICAgICAgIkVHTE4zIiwgIkZJTElQMUwiLCAiRk9YQzEiLCAiQURHUkwzIiwgIkZTVCIsICJFRk5CMiIsICJTRU1BNUEiLAojICAgICAgICAgICAgICAgICAiRkdGUjEiLCAiREFDSDEiLCAiRUdSMiIsICJDTEROMSIsICJDVEdGIiwgIkRFRkIxIiwgIkNBUkQxOCIsICJLUlQ2QSIsCiMgICAgICAgICAgICAgICAgICJTMTAwQTciLCAiS1JUNkIiLCAiTUdTVDEiLCAiQ0hJM0wxIiwgIkNDTDE5IiwgIkxHQUxTMSIsICJDWVAxQjEiLCAiVklNIikKCmZlYXR1cmVzX29pID0gYygiWUJYMyIsICJUWE5JUCIsICJLUlQxNCIsICJLUlQxNSIsICJORUFUMSIsCiAgICAgICAgICAgICAgICAiRlhZRDMiLCAiTVQyQSIsICJNVDFFIiwgIk1UMVgiLCAiQVFQMyIsICJHTFVMIiwKICAgICAgICAgICAgICAgICMgIkhBTExNQVJLX1RORkFfU0lHTkFMSU5HX1ZJQV9ORktCIgogICAgICAgICAgICAgICAgIkZPUyIsICJKVU5CIiwgIkRVU1AxIiwgIlpGUDM2IiwgIk5GS0JJWiIsCiAgICAgICAgICAgICAgICAiQVRGMyIsICJSSE9CIiwgICJFVFMyIiwgIklMMTgiLCAiS0xGNCIsICJLTEY2IiwgIktMRjkiLAogICAgICAgICAgICAgICAgIktMRjMiLCAiS0xGNSIsICJDT0wxN0ExIiwgIlRIU0Q0IiwgIldOVDMiLCAiV05UNCIsICJTTFBJIiwgIlBMQVQiLAogICAgICAgICAgICAgICAgIkxBTUI0IiwgIkRDTiIsICJTUElOSzUiLAogICAgICAgICAgICAgICAgIkdTVE0zIiwgIkFMREgzQTEiLCAgIkxHQUxTN0IiLCAiU0xDMzhBMiIsICJFSEYiLCAgIkNMRUMyQiIsCiAgICAgICAgICAgICAgICAiSUwyMFJCIiwgIklMMVIyIiwgIklGSTI3IiwgIkNYQ0wxNCIsICJITEEtQyIsICJHUFNNMiIsICJEQUFNMSIsICAgIklEMSIsCiAgICAgICAgICAgICAgICAiUk5BU0VUMiIsICJIT1BYIiwgIlBPVTNGMSIsICJTUFJZMSIsICJBUiIsICJQREdGQyIsCiAgICAgICAgICAgICAgICAiV0ZEQzIiLCAiV0ZEQzUiLCAiVFNDMjJEMyIsICJGR0ZSMyIsICAiTFk2RCIsICJJR0ZCUDMiLCAKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyBPdGhlciBPUlMKICAgICAgICAgICAgICAgICJBUE9FIiwgIkNUU0IiLCAiQ0FMRDEiLCAiU09YNCIsCiAgICAgICAgICAgICAgICAiU1RNTjEiLCAiTE1PNCIsICJDRUJQQiIsICJUTUVNNDVBIiwgIkdQWDIiLCAiQzFRVE5GMTIiLCAiR0pCNiIsCiAgICAgICAgICAgICAgICAiS1JUNkEiLCAiS1JUMTciLCAiUkJQMSIsICJDQUxNTDMiLCAiUFROIiwgIkRBUEsyIiwKICAgICAgICAgICAgICAgICJFR0xOMyIsICJGSUxJUDFMIiwgIkFER1JMMyIsICJGU1QiLCAiRUZOQjIiLCAiU0VNQTVBIiwKICAgICAgICAgICAgICAgICJGR0ZSMSIsICJFR1IyIiwgIkNMRE4xIiwgIkRFRkIxIiwgIkNBUkQxOCIsICJNR1NUMSIpCgpTZXVyYXQ6OkRvdFBsb3Qoc3Vic29iaiwKICAgICAgICAgICAgICAgIGFzc2F5ID0gIlJOQSIsCiAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGZlYXR1cmVzX29pLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2FtcGxlX3R5cGUiLAogICAgICAgICAgICAgICAgc2NhbGUgPSBGQUxTRSkgKwogIGdncGxvdDI6OmNvb3JkX2ZsaXAoKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGFxdWFyaXVzOjpjb2xvcl9nZW5lKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQpgYGAKCkhlYXRtYXAgZm9yIGNsdXN0ZXIgNSB2cyBvdGhlciBPUlMgOgoKYGBge3IgZmlnX2libG9yc19oZWF0bWFwX2NsdXN0ZXI1LCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDE5LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyBNYXRyaXgKbWF0X2V4cHIgPSBTZXVyYXQ6OkdldEFzc2F5RGF0YShzdWJzb2JqKQptYXRfZXhwciA9IG1hdF9leHByW2ZlYXR1cmVzX29pLCBdCm1hdF9leHByID0gTWF0cml4Ojp0KG1hdF9leHByKQptYXRfZXhwciA9IGR5bnV0aWxzOjpzY2FsZV9xdWFudGlsZShtYXRfZXhwcikgIyBiZXR3ZWVuIDAgYW5kIDEKbWF0X2V4cHIgPSBNYXRyaXg6OnQobWF0X2V4cHIpCmRpbShtYXRfZXhwcikgIyBnZW5lcyB4IGNlbGxzCgojIyBDb2xvcnMKbGlzdF9jb2xvcnMgPSBsaXN0KCkKbGlzdF9jb2xvcnNbWyJleHByZXNzaW9uIl1dID0gcmV2KFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChuYW1lID0gIlJkQnUiLCBuID0gOSkpCmxpc3RfY29sb3JzW1sic2FtcGxlX3R5cGUiXV0gPSBzYW1wbGVfdHlwZV9jb2xvcnMKbGlzdF9jb2xvcnNbWyJzYW1wbGVfaWRlbnRpZmllciJdXSA9IHNldE5hbWVzKG5tID0gc2FtcGxlX2luZm8kc2FtcGxlX2lkZW50aWZpZXIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVfaW5mbyRjb2xvcikKbGlzdF9jb2xvcnNbWyJzZXVyYXRfY2x1c3RlcnMiXV0gPSBzZXROYW1lcyhhcXVhcml1czo6Z2dfY29sb3JfaHVlKGxlbmd0aChsZXZlbHMoc3Vic29iaiRzZXVyYXRfY2x1c3RlcnMpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm0gPSBsZXZlbHMoc3Vic29iaiRzZXVyYXRfY2x1c3RlcnMpKQpsaXN0X2NvbG9yc1tbInNldXJhdF9jbHVzdGVycyJdXSA9IGxpc3RfY29sb3JzW1sic2V1cmF0X2NsdXN0ZXJzIl1dW3VuaXF1ZShzdWJzb2JqJHNldXJhdF9jbHVzdGVycyldCgojIENlbGxzIG9yZGVyCmNvbHVtbl9vcmRlciA9IHN1YnNvYmpAbWV0YS5kYXRhICU+JQogIGRwbHlyOjphcnJhbmdlKHNhbXBsZV90eXBlLCBzYW1wbGVfaWRlbnRpZmllcikgJT4lCiAgcm93bmFtZXMoKQpjb2x1bW5fb3JkZXIgPSBtYXRjaChjb2x1bW5fb3JkZXIsIHJvd25hbWVzKHN1YnNvYmpAbWV0YS5kYXRhKSkKCiMgQW5ub3RhdGlvbgpoYV90b3AgPSBIZWF0bWFwQW5ub3RhdGlvbihzYW1wbGVfdHlwZSA9IHN1YnNvYmokc2FtcGxlX3R5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbXBsZV9pZGVudGlmaWVyID0gc3Vic29iaiRzYW1wbGVfaWRlbnRpZmllciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3RlcnMgPSBzdWJzb2JqJHNldXJhdF9jbHVzdGVycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gbGlzdChzYW1wbGVfdHlwZSA9IGxpc3RfY29sb3JzW1sic2FtcGxlX3R5cGUiXV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FtcGxlX2lkZW50aWZpZXIgPSBsaXN0X2NvbG9yc1tbInNhbXBsZV9pZGVudGlmaWVyIl1dLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJzID0gbGlzdF9jb2xvcnNbWyJzZXVyYXRfY2x1c3RlcnMiXV0pKQoKIyBIZWF0bWFwCmh0ID0gSGVhdG1hcChhcy5tYXRyaXgobWF0X2V4cHIpLAogICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KHRpdGxlID0gIkV4cHJlc3Npb24iLCBhdCA9IGMoMCwgMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImxvdyIsICJoaWdoIikpLAogICAgICAgICAgICAgY29sID0gbGlzdF9jb2xvcnNbWyJleHByZXNzaW9uIl1dLAogICAgICAgICAgICAgdG9wX2Fubm90YXRpb24gPSBoYV90b3AsCiAgICAgICAgICAgICAjIENlbGwgZ3JvdXBpbmcKICAgICAgICAgICAgIGNvbHVtbl9zcGxpdCA9IHN1YnNvYmokc2FtcGxlX3R5cGUgJT4lIGFzLmNoYXJhY3RlcigpLAogICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gVFJVRSwKICAgICAgICAgICAgIGNvbHVtbl90aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgICAgICBzaG93X2NvbHVtbl9uYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgIyBHZW5lcwogICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICByb3dfbmFtZXNfZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gMTQsIGZvbnRmYWNlID0gInBsYWluIiksCiAgICAgICAgICAgICAjIFN0eWxlCiAgICAgICAgICAgICB1c2VfcmFzdGVyID0gRkFMU0UsCiAgICAgICAgICAgICBzaG93X2hlYXRtYXBfbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgIGJvcmRlciA9IFRSVUUpCgpDb21wbGV4SGVhdG1hcDo6ZHJhdyhodCwKICAgICAgICAgICAgICAgICAgICAgbWVyZ2VfbGVnZW5kID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iLAogICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKR2VuZXMgb2YgaW50ZXJlc3QgOgoKYGBge3IgZmlnX2libG9yc19nZW5lcywgZmlnLndpZHRoID0gMiwgZmlnLmhlaWdodCA9IDJ9CmdlbmVzID0gYygiS1JUMTYiLCAiQ09MMTdBMSIsICJEU1QiLCAiS1JUNkIiLCAiSUwxUjIiLCAiV05UMyIsCiAgICAgICAgICAiSUZJMjciLCAiQ1hDTDE0IiwgIklHRkJQMyIsICJLUlQxNSIsICJDRDIwMCIpCgpwbG90X2xpc3QgPSBsYXBwbHkoYygxOmxlbmd0aChnZW5lcykpLCBGVU4gPSBmdW5jdGlvbihnZW5lX2lkKSB7CiAgZ2VuZSA9IGdlbmVzW1tnZW5lX2lkXV0KICAKICBzb2JqX2libG9ycyRteV9nZW5lID0gU2V1cmF0OjpGZXRjaERhdGEoc29ial9pYmxvcnMsIGdlbmUpWywgMV0gJT4lCiAgICBhcXVhcml1czo6cnVuX3Jlc2NhbGUoLiwgbmV3X21pbiA9IDAsIG5ld19tYXggPSAxMCkKICAKICBTZXVyYXQ6OkZlYXR1cmVQbG90KHNvYmpfaWJsb3JzLCBmZWF0dXJlcyA9ICJteV9nZW5lIiwgcmVkdWN0aW9uID0gbmFtZTJELCBwdC5zaXplID0gMC4yNSkgKwogICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfZ3JhZGllbnRuKGNvbG9ycyA9IGFxdWFyaXVzOjpjb2xvcl9nZW5lLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAxMCwgYnkgPSAyLjUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIm1pbiIsIHJlcCgiIiwgMyksICJtYXgiKSkgKwogICAgZ2dwbG90Mjo6bGFicyh0aXRsZSA9IGdlbmUpICsKICAgIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTcpLAogICAgICAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE1KSwKICAgICAgICAgICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksCiAgICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIFNldXJhdDo6Tm9BeGVzKCkKfSkKCnBsb3RfbGlzdApgYGAKCgojIEhGU0NzIHRvIElCTCBhbmQgT1JTCgojIyBTZXR0aW5ncwoKV2UgbG9hZCB0aGUgbWVyZ2VkIGRhdGFzZXQgOgoKYGBge3Igc29ial90cmFqfQpzb2JqX3RyYWogPSByZWFkUkRTKHBhc3RlMChkYXRhX2RpciwgIi80X3pvb20vNF96b29tX2hmc2NfaWJsbW9ycy9oZnNjX2libG1vcnNfc29ial90cmFqX3RpbmdhLnJkcyIpKQpzb2JqX3RyYWoKYGBgCgoKVGhpcyBpcyB0aGUgcHJvamVjdGlvbiBuYW1lIHRvIHZpc3VhbGl6ZSBjZWxscyA6CgpgYGB7ciBzb2JqX25hbWUyRF90cmFqfQpuYW1lMkQgPSAiaGFybW9ueV9kbSIKYGBgCgpXZSBsb2FkIHRoZSB0cmFqZWN0b3J5IG9iamVjdCBmb3IgdmlzdWFsaXNhdGlvbiBwdXJwb3NlIDoKCmBgYHtyIGxvYWRfdHJhan0KbXlfdHJhaiA9IHJlYWRSRFMocGFzdGUwKGRhdGFfZGlyLCAiLzRfem9vbS80X3pvb21faGZzY19pYmxtb3JzL2hmc2NfaWJsbW9yc19teV90cmFqX3RpbmdhLnJkcyIpKQpjbGFzcyhteV90cmFqKQpgYGAKCgojIyBQcmVwYXJhdGlvbgoKV2UgZGVmaW5lZCBjZWxsIHR5cGUgYmFzZWQgb24gaW5kaXZpZHVhbCBvYmplY3QgOgoKYGBge3IgY2x1c3Rlcl90eXBlX3RyYWosIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA1fQpzb2JqX2libG9ycyRjZWxsX2JjID0gY29sbmFtZXMoc29ial9pYmxvcnMpCnNvYmpfdHJhaiRjZWxsX2JjID0gY29sbmFtZXMoc29ial90cmFqKQpzb2JqX3RyYWokY2x1c3Rlcl90eXBlID0gZHBseXI6OmxlZnRfam9pbihzb2JqX3RyYWpAbWV0YS5kYXRhWywgYygiY2VsbF9iYyIsICJwZXJjZW50Lm10IildLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb2JqX2libG9yc0BtZXRhLmRhdGFbLCBjKCJjZWxsX2JjIiwgImNsdXN0ZXJfdHlwZSIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiY2VsbF9iYyIpWywgImNsdXN0ZXJfdHlwZSJdICU+JSBhcy5jaGFyYWN0ZXIoKQpzb2JqX3RyYWokY2x1c3Rlcl90eXBlID0gaWZlbHNlKGNvbG5hbWVzKHNvYmpfdHJhaikgJWluJSBjb2xuYW1lcyhzb2JqX2hmc2MpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllcyA9ICJIRlNDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubyA9IHNvYmpfdHJhaiRjbHVzdGVyX3R5cGUpICU+JQogIGFzLmZhY3RvcigpCmBgYAoKIyMgRmlndXJlcwoKQ2VsbHMgb24gdGhlIGZ1bGwgYXRsYXMgOgoKYGBge3IgZmlnX3RyYWpfbG9jYXRpb24sIGZpZy53aWR0aCA9IDIsIGZpZy5oZWlnaHQgPSAyfQpzb2JqJGNlbGxfYmMgPSBjb2xuYW1lcyhzb2JqKQpzb2JqX3RyYWokY2VsbF9iYyA9IGNvbG5hbWVzKHNvYmpfdHJhaikKc29iaiRpc190cmFqID0gZHBseXI6OmxlZnRfam9pbihzb2JqQG1ldGEuZGF0YVssIGMoImNlbGxfYmMiLCAicGVyY2VudC5tdCIpXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb2JqX3RyYWpAbWV0YS5kYXRhWywgYygiY2VsbF9iYyIsICJjbHVzdGVyX3R5cGUiKV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAiY2VsbF9iYyIpWywgImNsdXN0ZXJfdHlwZSJdCgpTZXVyYXQ6OkRpbVBsb3Qoc29iaiwgcmVkdWN0aW9uID0gbmFtZTJEX2F0bGFzLCBwdC5zaXplID0gMC4wMDAwMDEsCiAgICAgICAgICAgICAgICBncm91cC5ieSA9ICJpc190cmFqIiwgb3JkZXIgPSBsZXZlbHMoc29ial90cmFqJGNsdXN0ZXJfdHlwZSkpICsKICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyhjb2xvcl9tYXJrZXJzW2MoIklCTCIsICJPUlMiLCAiSEZTQyIpXSwgYmdfY29sb3IpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKCJJQkwiLCAiT1JTIiwgIkhGU0MiLCBOQSksIG5hLnZhbHVlID0gYmdfY29sb3IpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCgpQcm9qZWN0IG5hbWUgOgoKYGBge3IgZmlnX3RyYWpfcHJvamVjdF9uYW1lLCBmaWcud2lkdGggPSA0LCBmaWcuaGVpZ2h0ID0gNH0KIyBSYW5kb20gb3JkZXIKc2V0LnNlZWQoMTIzNCkKcm5kX29yZGVyID0gc2FtcGxlKGNvbG5hbWVzKHNvYmpfdHJhaiksIHJlcGxhY2UgPSBGQUxTRSwgc2l6ZSA9IG5jb2woc29ial90cmFqKSkKCiMgRXh0cmFjdCBjb29yZGluYXRlcwpjZWxsc19jb29yZCA9IHNvYmpfdHJhakByZWR1Y3Rpb25zW1tuYW1lMkRdXUBjZWxsLmVtYmVkZGluZ3MgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JQogIGBjb2xuYW1lczwtYChjKCJEaW0xIiwgIkRpbTIiKSkKY2VsbHNfY29vcmQkcHJvamVjdF9uYW1lID0gc29ial90cmFqJHByb2plY3RfbmFtZQpjZWxsc19jb29yZCA9IGNlbGxzX2Nvb3JkWyhybmRfb3JkZXIpLCBdCgojIFBsb3QKZ2dwbG90Mjo6Z2dwbG90KGNlbGxzX2Nvb3JkLCBhZXMoeCA9IERpbTEsIHkgPSBEaW0yLCBjb2wgPSBwcm9qZWN0X25hbWUpKSArCiAgZ2dwbG90Mjo6Z2VvbV9wb2ludChzaXplID0gMS4yKSArCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHNhbXBsZV9pbmZvJGNvbG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzYW1wbGVfaW5mbyRwcm9qZWN0X25hbWUpICsKICBnZ3Bsb3QyOjp0aGVtZV92b2lkKCkgKwogIGdncGxvdDI6OnRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCkNsdXN0ZXIgOgoKYGBge3IgZmlnX3RyYWpfY2x1c3RlcnMsIGZpZy53aWR0aCA9IDQsIGZpZy5oZWlnaHQgPSA0fQpTZXVyYXQ6OkRpbVBsb3Qoc29ial90cmFqLCByZWR1Y3Rpb24gPSBuYW1lMkQsIHB0LnNpemUgPSAxLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgbGFiZWwgPSBUUlVFKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSkgKwogIFNldXJhdDo6Tm9BeGVzKCkgKwogIFNldXJhdDo6Tm9MZWdlbmQoKQpgYGAKCkNsdXN0ZXIgdHlwZSA6CgpgYGB7ciBmaWdfdHJhal9jbHVzdGVyX3R5cGUsIGZpZy53aWR0aCA9IDIsIGZpZy5oZWlnaHQgPSAyfQpTZXVyYXQ6OkRpbVBsb3Qoc29ial90cmFqLCByZWR1Y3Rpb24gPSBuYW1lMkQsIHB0LnNpemUgPSAxLAogICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAiY2x1c3Rlcl90eXBlIiwgY29scyA9IGNvbG9yX21hcmtlcnMpICsKICBnZ3Bsb3QyOjp0aGVtZShhc3BlY3QucmF0aW8gPSAxKSArCiAgU2V1cmF0OjpOb0F4ZXMoKSArCiAgU2V1cmF0OjpOb0xlZ2VuZCgpCmBgYAoKUHNldWRvdGltZSA6CgpgYGB7ciBmaWdfdHJhal9wc2V1ZG90aW1lLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNH0KU2V1cmF0OjpGZWF0dXJlUGxvdChzb2JqX3RyYWosIHJlZHVjdGlvbiA9IG5hbWUyRCwgcHQuc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJwc2V1ZG90aW1lIikgKwogIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnMgPSB2aXJpZGlzOjp2aXJpZGlzKG4gPSAxMDApKSArCiAgZ2dwbG90Mjo6bGltcyh4ID0gcmFuZ2Uoc29ial90cmFqQHJlZHVjdGlvbnNbW25hbWUyRF1dQGNlbGwuZW1iZWRkaW5nc1ssIDFdKSwKICAgICAgICAgICAgICAgIHkgPSByYW5nZShzb2JqX3RyYWpAcmVkdWN0aW9uc1tbbmFtZTJEXV1AY2VsbC5lbWJlZGRpbmdzWywgMl0pKSArCiAgZ2dwbG90Mjo6dGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgU2V1cmF0OjpOb0F4ZXMoKQpgYGAKClBzZXVkb3RpbWUgd2l0aCBkeW5wbG90J3MgZnVuY3Rpb24gOgoKYGBge3IgZmlnX3RyYWpfcHNldWRvdGltZV9keW5wbG90LCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gNn0KZHlucGxvdDo6cGxvdF9kaW1yZWQodHJhamVjdG9yeSA9IG15X3RyYWosCiAgICAgICAgICAgICAgICAgICAgIGRpbXJlZCA9IHNvYmpfdHJhaltbbmFtZTJEXV1AY2VsbC5lbWJlZGRpbmdzLAogICAgICAgICAgICAgICAgICAgICAjIENlbGxzCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2NlbGxzID0gJ3BzZXVkb3RpbWUnLAogICAgICAgICAgICAgICAgICAgICBzaXplX2NlbGxzID0gMS42LAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfcmFkaXVzX3BlcmNlbnRhZ2UgPSAwLAogICAgICAgICAgICAgICAgICAgICAjIFRyYWplY3RvcnkKICAgICAgICAgICAgICAgICAgICAgcGxvdF90cmFqZWN0b3J5ID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgY29sb3JfdHJhamVjdG9yeSA9ICJub25lIiwKICAgICAgICAgICAgICAgICAgICAgbGFiZWxfbWlsZXN0b25lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICBzaXplX21pbGVzdG9uZXMgPSAwLAogICAgICAgICAgICAgICAgICAgICBzaXplX3RyYW5zaXRpb25zID0gMSkKYGBgCgojIFIgU2Vzc2lvbgoKYGBge3Igc2Vzc2lvbmluZm8sIGVjaG8gPSBGQUxTRSwgZm9sZF9vdXRwdXQgPSBUUlVFfQpzZXNzaW9uSW5mbygpCmBgYAoK